24

I'm observing a bizarre thing: in the new widgets far too often remote images are not being displayed even though the image has been successfully loaded and placed in cache.

For image downloading I've tried:

  • SDWebImageSwiftUI
  • Kingfisher
  • SwURL

All of them indicate that image loading succeed, but the actual widget is not showing it.

struct TestWidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        WebImage(url: URL(string: "https://miro.medium.com/max/3840/0*TLqp5Uwavd-U_xrs.jpg"))
                        .onSuccess()
                        .resizable()
    }
}

On the second run of the debugger - with image loading from cache - I get the image displayed, but never(?) on initial run.

It feels like that in onSuccess I need to trigger UI-invalidation? But how?

(Since it happens to literally every image-lib I try - I don't think that it's something off in the libs)

Environment:

  • iOS 14 Beta 3 (both device and simulators)
  • Xcode 12 Beta 3
  • During the debug run, memory use is around 15mb
Konstantin Loginov
  • 15,802
  • 5
  • 58
  • 95
  • I can display the image on the widget by RemoteImage, but sometime it will not display due to widget policy. Might be the same problem here – Neo.Mxn0 Nov 23 '20 at 03:28

2 Answers2

49

Yes, as mentioned by Konstantin, it is not supported to load images asynchronously. There are 2 options to load network image in widgets

  1. Either fetch all the images in TimelineProvider and inject them to the views directly.

    OR

  2. Use Data(contentsOf: url) to fetch the image. This way it still fetches them synchronously but the code is cleaner. Sample code -

    struct NetworkImage: View {
    
      private let url: URL?
    
      var body: some View {
    
        Group {
         if let url = url, let imageData = try? Data(contentsOf: url), 
           let uiImage = UIImage(data: imageData) {
    
           Image(uiImage: uiImage)
             .resizable()
             .aspectRatio(contentMode: .fill)
          } 
          else {
           Image("placeholder-image")
          }
        }
      }
    
    }
    

This view can simply be use like this -

NetworkImage(url: url)
prad
  • 1,086
  • 1
  • 11
  • 19
9

Got it: it's simply not supported and you aim to load images inside TimelineProvider:

https://developer.apple.com/forums/thread/652581

Konstantin Loginov
  • 15,802
  • 5
  • 58
  • 95
  • This helps me a lot, I've been struggling for this for whole night, thanks! – Johnny Nov 21 '20 at 13:18
  • Does it mean I cannot use SwiftUI component (eg: https://github.com/dmytro-anokhin/url-image) to render image? Should I predownload the image binary into local in TImelineProvider first? – Neo.Mxn0 Nov 23 '20 at 03:26