LazyVgrid image loading from CoreData

Can anyone help me with this? I try to use the LazyVGrid and load images from CoreData stored in a binary data field. How can I make the image loading asynchronous? I have tried to look how ImageLoader's for remote images work, but I can't make it work with images loading from CoreData.

My ImageLoader works but the ScrollView freeze until all images are loaded.

Code Block
protocol ImageLoaderModel {
  func thumbnailData() -> Data?
  func thumbnailCacheKey() -> String
}
struct ContentView: View {
   
  @FetchRequest(
    entity: Item.entity(),
    sortDescriptors: [NSSortDescriptor(key: "name", ascending: true)]
  ) private var items: FetchedResults<Item>
   
  var columns: [GridItem] = [
    GridItem(.adaptive(minimum: 150))
  ]
   
  var body: some View {
    ScrollView {
      LazyVGrid(columns: columns, alignment: .center, spacing: 20) {
        ForEach(items, id: \.self) { item in
          GridItemView(item: item)
        }
      }
      .padding()
    }
  }
   
}
struct GridItemView: View {
   
  @ObservedObject var item: Item
  var body: some View {
    VStack(alignment: .center) {
       
      if item.thumbnail != nil {
        AsyncImage(model: item)
      } else {
        RoundedRectangle(cornerRadius: 5)
          .frame(width: 150, height: 112)
      }
       
      Text(item.name ?? "")
        .font(.subheadline)
       
    }
  }
   
}
struct AsyncImage: View {
   
  @ObservedObject private var loader: ImageLoader
   
  init(model: ImageLoaderModel) {
    loader = ImageLoader(model: model)
  }
   
  var body: some View {
    image.onAppear(perform: loader.load)
  }
   
  private var image: some View {
    Group {
      if loader.uiImage != nil {
        Image(uiImage: loader.uiImage!)
          .resizable()
          .scaledToFill()
          .frame(width: 150, height: 112)
          .cornerRadius(5)
          .clipped()
      } else {
        ProgressView()
          .frame(width: 150, height: 112)
      }
    }
  }
   
}
class ImageLoader: ObservableObject {
   
  @Published var uiImage: UIImage?
   
  private var model: ImageLoaderModel
  private var cache = ImageCache.shared
   
  init(model: ImageLoaderModel) {
    self.model = model
  }
   
  func load() {
     
    let cacheKey = self.model.thumbnailCacheKey()
     
    if let uiImage = cache[cacheKey] {
      self.uiImage = uiImage
      return
    }
     
    DispatchQueue.global(qos: .userInitiated).async { [weak self] in
      guard let data = self?.model.thumbnailData() else { return }
      if let uiImage = UIImage(data: data) {
        DispatchQueue.main.async {
          self?.cache[cacheKey] = uiImage
          self?.uiImage = uiImage
          return
        }
      }
    }
     
  }
   
}


Replies

Having this issue too. Did you ever resolve?