I'm having a hard time managing a shared core data object. I'm hoping that I'm doing something wrong and it's not just a bug in the cloudkit sharing but I also tried it with a sample app from apple with the same issue.
Here's what I'm doing:
When sharing a new object, I call the UICloudSharingController
like so:
let cloudSharingController = UICloudSharingController {
(controller, completion: @escaping (CKShare?, CKContainer?, Error?) -> Void) in
container.share([myObject], to: nil) { objectIDs, share, container, error in
if let actualShare = share {
myObject.managedObjectContext?.performAndWait {
actualShare[CKShare.SystemFieldKey.title] = myObject.title
}
}
completion(share, container, error)
}
}
cloudSharingController.delegate = self
present(cloudSharingController, animated: true)
this opens the system sharing dialog. I select "Messages" for example and it opens the messages app with the preview of the share, just fine. Now when I cancel the share is where things get interesting. This pretty much breaks my whole application. I can no longer share this object or any other object again. I always get an error CKError 0x281611dd0: "Internal Error" (1/5002); "Couldn't encode share PCS data"
so it looks something is corrupted from that point on. The same also happens if I remove the last person from a share.
I checked the CloudKit console and from what I can see the problem seems to be that the newly created zone is no longer shared. If I enable sharing for that zone again in the cloudkit console and restart the app, It works again and I can share again.
What's also broken, If I check if there is already a share for my object and present the UICloudSharingController
like so instead:
let controller = UICloudSharingController(share: share, container: CKContainer(identifier: myIdentifier))
controller.delegate = self self.present(controller, animated: true) it always has outdated data, the person I just removed, is still in there and I can also not add any new participants.
Do I really have to somehow figure out if a share has no more participants and delete it from the shared zone myself and create a deep copy back in my private zone. I'm having a hard time believing it would have to be THAT hacky. There has to be another way? Let me know if you need more insights with my implementation.
Unfortunately the CloudKit sharing implementation from Apple is not great (even though it was improved a couple of year ago). It is time consuming to get it "right" and you will likely be forced to write you own version of the UICloudSharingController to provide an optimal experience for end users as you can't really customise it (for example, hide the "Stop Sharing" or "Copy Link" buttons when not required). Also, the "sharing" terminology may not match what your users expect or understand.
If you do use it, I would recommend you create the ckShare yourself and then only present the controller using UICloudSharingController(share: , container:) as the other method can appear quite slow to users the first time (i.e. nothing seems to happen until the ckShare is finally created - which can sometime take more than 10 seconds).
But in my experience the best you can do is bite the bullet and build the capabilities you need into your own app without ever using UICloudSharingController. This project from Apple has an example where you use ShareLink once you have done everything you need with the ckShare. The project also has some good comments that warn you about common pitfalls: https://developer.apple.com/documentation/coredata/sharing_core_data_objects_between_icloud_users
-- As a side note, please also be aware that the sharing process can easily fail when sending the invitation using email (best to stick to Messages or AirDrop) because the email client of the recipient may not be compatible. If so, they won't able to accept the invitation by tapping it on it. They'll get some cryptic error message. As a workaround, they can copy the link into a compatible app (e.g. Note) but by that time they'll probably have deleted your app...