Share Core Data between users with NSPersistentCloudKitContainer
Asked Answered
A

3

16

Apple introduced the NSPersistentCloudKitContainer with iOS 13 which enable us to use CloudKit with Core Data. I got it working pretty much instantly on different devices but my main issue is still left.

Is it possible to share the data in an easy way with other users? I've been reading on CKShare but don't see how I can go from NSPersistentCloudKitContainer to that in an easy way.

Allhallowmas answered 26/6, 2019 at 8:44 Comment(4)
I don't believe that you can - If you use straight CloudKit then you can either choose to create records in the public database (which are then accessible by all users of your app) or you can choose to share specific records from the private database by using CKShare - When you use NSPersistentCloudKitContainer the CloudKit implementation is hidden from you, so you can't create the required CKShareMak
@Mak You should write that as an answer to this question, because I believe what you said is correct. :)Neve
Did you yet find the answer? It seems we could easily add the CKShare to a mirrored record in the mirroring zone, but the question still remain on how to sync it back when it appears on the shared database on the other side.Around
I could retrieve the CKRecord and create a CKShare (see my comment at the answer of orange). Unfortunately this won't work since this shares will never appear in a shared database zone... maybe the next WWDC will help or bring us answersFarina
G
8

As announced in WWDC 2021, you can now share to other iCloud users. https://developer.apple.com/videos/play/wwdc2021/10015/

Glair answered 14/6, 2021 at 7:41 Comment(0)
D
4

It seems this is now possible in iOS 14.0+ Beta and macOS 11.0+ Beta via the new databaseScope property: https://developer.apple.com/documentation/coredata/nspersistentcloudkitcontaineroptions/3580372-databasescope

The possible values are .public (the public database), .private (the private database) and .shared (the shared database).

E.g.:

let container = NSPersistentCloudKitContainer(name: "test")
guard let description = container.persistentStoreDescription.first else {
fatalError("Error")
}
description.cloudKitContainerOptions?.databaseScope = .shared

The video https://developer.apple.com/videos/play/wwdc2020/10650 describes how to sync the Core Data store with the CloudKit public database by setting the databaseScope value to .public.

[UPDATE] Unfortunately, it seems sharing is not (yet?) supported, even though the databaseScope = .shared property suggests otherwise. Please refer to https://developer.apple.com/forums/thread/649630?login=true&page=1#621748022 as pointed out by Brian M below.

Doorstop answered 25/6, 2020 at 22:39 Comment(12)
It's available for public database, but not available for shared database. It must be done by obtaining CKRecord from NSManagedObjectID. Here, you can create a CKShare. And you need to subscribe to CKDatabaseSubscription.Appreciate
@FlorentMorin Were you able to find docs about it being public only and not shared?Sense
This answer from an Apple engineer doesn't sound promising. developer.apple.com/forums/thread/…. @FlorentMorin or Bas the Developer, do either of you have this working?Debauch
@Sense : Last WWDC session about CloudKit + Core Data developer.apple.com/wwdc20/10650Appreciate
@BrianM Not tried for now. If it must be done manually, via shared database, I think I will do everything in app manually.Appreciate
@BrianM I could not get it to work. Given the answers of the Apple engineers, it seems we have to write the entire sharing code ourselves and that is not something that I am going to try to code myself.Doorstop
Bas you're smart - it's a ton of work (especially if you use it to learn swift and iOS development which is what I did). I need to refactor my existing CloudKit sharing system which I've spent literally 3 million hours working on and is about 99% reliable. It's hard to want to put in more time knowing how easy it's going to be in just 1 more year...Debauch
I can see from @ricardopereria update that still can’t do this using a shared scope. Has there been any progress on this that you guys have see? I basically want to enable sharing of data between users without it being public scope.Norman
Hey @Jules, I had to create full sync by myself and not using NSPersistentCloudKitContainer at all because of that sharing((( Spent a lot of time but no other way to implement sharing for now.Figment
Hey @Figment I can imagine that was a right pain, good job, I want to create several apps using sync and NSPersistantCloudKitContainer massively reduces the complexity. I’ve unfortunately decided to wait until this functionality is available, wasted a lot of time on iCloud in the past 🙁Norman
@Norman That can be a right choice in some cases to wait, but my app will not be really cool among competitors without sharing and we have no idea when Apple will give us shared DB sync from the box. The pain was really huge, especially because my model contains relationships (thankfully it's simple relationships).Figment
@Figment I’d love to have that functionalityNorman
F
2

There are methods on NSPersistentCloudKitContainer for accessing the underlying cloudkit records: https://developer.apple.com/documentation/coredata/nspersistentcloudkitcontainer. For example,

func record(for managedObjectID: NSManagedObjectID) -> CKRecord?

So in theory you could use this method to obtain a CKRecord then create a CKShare manually.

BUT as of the current beta release (beta 3) these methods seem to return nil. It seems like they wouldn't have included these methods if they wanted to keep the implementation hidden. So we're in this spot where you can implement the entire sync yourself and get sharing, or use their sync implementation but not get sharing. I hope the lack of implementation on these methods is simply an early beta issue.

Florist answered 8/7, 2019 at 21:1 Comment(2)
I did manage to get the record and also to create a CKShare out of it ... but in the end CoreData's CloudKit container will never appear in a shared zone.... maybe we will have to wait to the next WWDC - keep the fingers crossed.Farina
Anyone made this successfully? I've implemented setting up parent records, BUT sometimes fetching Core Data is crashing CoreDataMirroring (when I do that on internet restore) and it show me "Probably no internet" until I restart an app. Core Data don't have any callbacks or state checking, so I don't have ability to do stuff other than sometimes simultaneously with automated CoreData+CloudKit Mirroring.Figment

© 2022 - 2024 — McMap. All rights reserved.