1

This is my simple class file:

import SwiftUI
struct NetworkImage: View {
    let url: URL?
    var body: some View {
//1st part
        if let url = URL(string: "https://thumbs.dreamstime.com/b/tiger-portrait-horizontal-11392212.jpg"),
            let imageData = try? Data(contentsOf: url),
            let uiImage = UIImage(data: imageData) {
            Image(uiImage: uiImage)
                .centerCropped()
        }
// 2nd part
            AsyncImage(url: URL(string: "https://thumbs.dreamstime.com/b/tiger-portrait-horizontal-11392212.jpg")) { phase in
                if let image = phase.image {
                    image
                        .centerCropped()
                } else {
                    Image(systemName: "photo.fill")
                        .centerCropped()
                        .opacity(0.3)
                }
            }
}
extension Image {
    func centerCropped() -> some View {
        GeometryReader { geo in
            self
            .resizable()
            .scaledToFill()
                .frame(width: geo.size.width, height: geo.size.height)
            .clipped()
        }
    }
}

This is the result for first part:

enter image description here

and this one for second:

enter image description here

Why doesn't it work correctly on iOS widgets? The same code loads image very good on watchOS.

halfer
  • 19,824
  • 17
  • 99
  • 186
Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358
  • Widgets don’t listen or update my guess would be that AsyncImage relies on SwiftUI wrappers to listen when the download is complete. – lorem ipsum Mar 18 '23 at 10:27
  • What do you mean?;) Because I dont understand. SwiftUI wrappers?;) – Bartłomiej Semańczyk Mar 18 '23 at 11:31
  • SwiftUI depends on wrappers that conform to DynamicProperty to tell it when to reload the body. Widgets can’t reload the body. No SwiftUI wrappers work like they do in iOS or watchOS. AsyncImage likely has a wrapper within it to reload its body when the download is done. Since wrappers don’t work async image doesn’t work. – lorem ipsum Mar 18 '23 at 11:42
  • Widgets are like a GIF and each Entry is like an image that makes the GIF. If the data doesn’t exist in get timeline when you are making the gif/entries then it won’t exist at any other point. – lorem ipsum Mar 18 '23 at 11:44
  • So, there is no possibility to use AsyncImage in widgets? Any alternative? – Bartłomiej Semańczyk Mar 18 '23 at 12:18
  • 1
    Nothing else right now. Widgets are meant to be low weight. But it may change in June there has been quite a bit of talk about animations for widgets which isn’t possible for the same reasons. This is just a hunch though nothing concrete. – lorem ipsum Mar 18 '23 at 12:22
  • So the only thing for widgets is now using 1st part of my code. But sometimes it is very heavy for my widgets and it crashes because of memory issue. Is there any way to make it less heavier? Maybe should I use AsyncImage before I call completion in `getTimeline`? – Bartłomiej Semańczyk Mar 18 '23 at 12:33
  • No, im surprised that works at all that Data initializer is usually used for local urls since it can’t handle any web issues. I don’t know if this is written anywhere. You can download the image data in get timeline with url session then put it somewhere or pass the data in the Entry. I use CoreData as a cache a lot for when widgets have to share data with apps. – lorem ipsum Mar 18 '23 at 12:37
  • downloading an image in `getTimeline` and then passing it in the Entry makes any difference to downloading an image inside widget view? – Bartłomiej Semańczyk Mar 18 '23 at 12:49
  • it does because the data is already there when the widget is actually showing the data it doesn't have to wait for the data to come from a url. – lorem ipsum Mar 18 '23 at 12:52
  • One more question. Is it possible that thing makes a crash for widget if about memory issue? – Bartłomiej Semańczyk Mar 18 '23 at 13:21
  • Maybe but doubt it – lorem ipsum Mar 18 '23 at 14:52

0 Answers0