I wasn’t positive learn how to phrase the query. I do know it is deceptive.
Context:
I am utilizing NSPersistentCloudKitContainer for my private and non-private database. The CoreData mannequin has two configurations: Native, Cloud. Native corresponds to the personal CloudKit database and Cloud to the general public CloudKit database. Each configurations include all objects: Checklist, ListItem, and Like.
Checklist has a to-many relationship to ListItem (with inverse).
ListItem has a to-many relationship to Like (with inverse).
The personal database implementation is working as anticipated.
A consumer can create lists and record objects. Every of those objects may be set as public or personal utilizing the attribute isPublic.
I’ve a singleton object that screens adjustments to Lists and ListItems utilizing the NSManagedObjectContextDidChange notification. If the consumer updates the isPublic attribute to true a replica of the Checklist or ListItem is created within the public database. If the consumer units isPublic to false, the Checklist or ListItem has an isTrashed attribute that is set to true within the public database (unsure when to truly delete the information from the general public database however, that is for an additional query).
The consumer may also view all ListItems within the public database utilizing a NSFetchedResultsController to load information and for monitor adjustments.
Drawback
I will show all public ListItems utilizing a UITableView and a NSFetchedResultsController. I’ve a customized UITableViewCell that shows the consumer who created the ListItem’s username and likes like so:
- Get the creatorUserRecordID for the NSManagedObject utilizing NSPersistentCloudKitContainer.document(for:)
- Get the Consumer CKRecord for the creatorUserRecordID utilizing CKContainer.default().publicCloudDatabase.document(for:)
- Entry the username of the Consumer CKRecord
I do that async name for each UITableViewCell. Is that this right? If that’s the case, I will must implement a caching mechanism.
Not solely that, what if the async name fails? Now, I’ve a UITableView cell that has a clean username. Ought to I prefetch the username for all objects within the NSFetchedResultsController beforehand? That could possibly be hundreds of objects that have not even been displayed and will increase loading time.
I assume my drawback is admittedly validation that I am going about this the right manner.
Is it right to async fetch the Consumer CKRecord of every ListItem or is there a greater solution to entry the consumer who created the CKRecord?
Ought to I create a customized Consumer NSManagedObject?
I might additionally prefer to show the usernames of every consumer who favored the record merchandise. Does this imply for each like I will must do the identical course of? Meaning I will have an API name for every username of every record merchandise and every like of every record merchandise ((1 + x) * y API calls; x = variety of likes, y = variety of record objects).
Say I am displaying 100 ListItems with a median of 20 likes. Meaning I will make:
(1 + 20) * 100 = 2100 API calls (with out caching)
That hits the 40 requests/second restrict with lower than 2 record objects.
If extra info is required or extra code, let me know.
It looks like my best choice is to create a customized Consumer object in my CoreData mannequin for the reason that NSPersistentCloudKitContainer setup is fetching relationships for me.
Pattern Code (UITableViewCell)
public func configure(listItem: ListItem, surroundings: Setting) {
self.listItem = listItem
self.surroundings = surroundings
self.userRecordId = self.surroundings?.coreDataStack.creatorUserRecordID(for: listItem)
self.fetchUserTask?.cancel()
self.fetchUserTask = Job {
guard let userRecordId = self.userRecordId,
let userRecord = strive? await CKContainer.default().publicCloudDatabase.document(for: userRecordId) else {
self.userNameLabel.textual content = "I am server poor. You'll be able to't view this info."
return
}
if !Job.isCancelled {
Job { @MainActor in
self.userRecord = userRecord
self.userNameLabel.textual content = self.userRecord?["username"]
}
}
}
self.contentTextView.textual content = listItem.title
self.dateCreatedLabel.textual content = DateFormatter.localizedString(
from: listItem.modifiedAt!,
dateStyle: .medium,
timeStyle: .quick
)
let likes = self.listItem?.likes
self.likeButton.setTitle("(likes?.depend ?? 0)", for: .regular)
if let likes = likes?.allObjects as? [Like] {
for like in likes {
guard let userRecordId = self.surroundings?.coreDataStack.creatorUserRecordID(for: like) else {
self.likeButton.isEnabled = false
proceed
}
if userRecordId.recordName == CKCurrentUserDefaultName {
self.likeButton.isEnabled = false
break
}
}
}
}