Hygison Brandao
Hygison Brandao

Reputation: 718

CoreData+CloudKit First time loading Data takes too long

I am having problems when I first loads the app. The time it takes for the Items to be sync from my CloudKit to my local CoreData is too long.

Code

I have the model below defined by my CoreData.

public extension Item {
    @nonobjc class func fetchRequest() -> NSFetchRequest<Item> {
        NSFetchRequest<Item>(entityName: "Item")
    }

    @NSManaged var createdAt: Date?
    @NSManaged var id: UUID?
    @NSManaged var image: Data?
    @NSManaged var usdz: Data?
    @NSManaged var characteristics: NSSet?
    @NSManaged var parent: SomeParent?
}

I made a Few tests loading the data when the app is downloaded for the first time. I am loading on my view using the below code:

@FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Item.createdAt, ascending: true)]
)
private var items: FetchedResults<Item>

var body: some View {
    VStack {
        ScrollView(.vertical, showsIndicators: false) {
            LazyVGrid(columns: columns, spacing: 40) {
                ForEach(items, id: \.self) { item in
                    Text(item.id)
                }
            }
        }
    }
}

Test 1 - Just loads everything

When I have on my cloudKit images and usdz a total of 100mb data, it takes around 140 seconds to show some data on my view (Not all items were sync, that takes much longer time)

Test 2 - Trying getting only 10 items at the time ()

This takes the same amount of times the long one . I have added the following in my class, and removed the @FetchRequest:

@State private var items: [Item] = [] // CK
@State private var isLoading = false
@MainActor
func loadMoreData() {
    guard !isLoading else { return }
    isLoading = true

    let fetchRequest = NSFetchRequest<Item>(entityName: "Item")
    fetchRequest.predicate = NSPredicate(format: "title != nil AND title != ''")
    fetchRequest.fetchLimit = 10
    fetchRequest.fetchOffset = items.count
    fetchRequest.predicate = getPredicate()
    fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \Item.createdAt, ascending: true)]

    do {
        let newItems = try viewContext.fetch(fetchRequest)
        DispatchQueue.main.async {
            items.append(contentsOf: newItems)
            isLoading = false
        }
    } catch {}
}

Test 2 - Remove all images and usdz from CloudKit set all as Null

Setting all items BinaryData to null, it takes around 8 seconds to Show the list.

So as we can see here, all the solutions that I found are bad. I just wanna go to my CloudKit and fetch the data with my CoreData. And if possible to NOT fetch all the data because that would be not possible (imagine the future with 10 or 20GB or data) What is the solution for this loading problem? What do I need to do/fix in order to load lets say 10 items first, then later on the other items and let the user have a seamlessly experience?

Questions

  1. What are the solutions I have when the user first loads the app?
  2. How to force CoreData to query directly cloudKit?
  3. Does CoreData + CloudKit + NSPersistentCloudKitContainer will download the whole CloudKit database in my local, is that good????
  4. Storing images as BinaryData with Allow external Storage does not seems to be working well, because it is downloading the image even without the need for the image right now, how should I store the Binary data or Images in this case?

Upvotes: -1

Views: 25

Answers (0)

Related Questions