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?
}
image and usdz columns are both marked as BinaryData and Attribute Allows External Storage is also selected.
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
What are the solutions I have when the user first loads the app?
How to force CoreData to query directly cloudKit?
Does CoreData + CloudKit + NSPersistentCloudKitContainer will download the whole CloudKit database in my local, is that good????
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?