4

I know this is a common question, maybe it is so many time asked before. Also I know how to share a single database with App Extensions using Core Data by enabling App Groups. I am now using the NSPersistentCloudKitContainer to sync the data (across iCloud devices), and works very well.

But I want to share my database with my App Extensions (Today Extension), at this time App Groups won't help anymore, because they are different technologies as Apple described. So I am simply enabled iCloud for both the container app and the app extension from Signing and Capabilities pane. Then I can access my single database from both app container/extension as shown below:

// MARK: - Core Data stack, Shared database
lazy var persistentContainer: NSPersistentCloudKitContainer = {
    let container = NSPersistentCloudKitContainer(name: "MyApp")

    // Spotlight search support and history tracking
    container.persistentStoreDescriptions.forEach {
        $0.setOption(CoreDataSpotlightSearchDelegate.init(forStoreWith: $0, model: container.managedObjectModel), forKey: NSCoreDataCoreSpotlightExporter)
        $0.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
    }
    
    // Load persistent store
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })

    container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    container.viewContext.automaticallyMergesChangesFromParent = true
    
    return container
}()

However it is only works when the device is online (which is expected behavior), so my question is:

Is it possible to share my database between app and extension while the device is offline using NSPersistentCloudKitContainer? Some workarounds?

EDIT

This is a non-working version, I can access the same database but without cloud-syncing (Not appears on the CloudKit Dashboard):

 // MARK: - Core Data stack, Shared database
lazy var persistentContainer: NSPersistentCloudKitContainer = {
    let container = NSPersistentCloudKitContainer(name: "MyApp")
    
    // Shared container support
    if let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.company.MyApp")?.appendingPathComponent("MyApp.sqlite") {
        let persistentStoreDescription = NSPersistentStoreDescription.init(url: url)
        container.persistentStoreDescriptions = [persistentStoreDescription]
    }

    // Spotlight search support and history tracking
    container.persistentStoreDescriptions.forEach {
        $0.setOption(CoreDataSpotlightSearchDelegate.init(forStoreWith: $0, model: container.managedObjectModel), forKey: NSCoreDataCoreSpotlightExporter)
    }
    
    // Load persistent store
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })

    container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    container.viewContext.automaticallyMergesChangesFromParent = true
    
    return container
}()
4
  • Please clarify what you mean by offline. Obviously an offline device cannot sync with the cloud because that requires an internet connection. Commented Aug 4, 2020 at 12:51
  • @malhal Yes of course, won’t sync as I mentioned above. So what I want to get? If the user made some changes from the container app while device is offline, I need to update the app extension (they’re shows the same data). Unfortunately it is not working. 2) Shared database with App Groups: Works great without a cloud syncing. 3) ? Commented Aug 4, 2020 at 13:28
  • Sync means the device syncing with the cloud. It sounds to me like you are talking about the app and the extension sharing the same database? Commented Aug 4, 2020 at 15:25
  • @malhal Exactly! I need to share my database with the app extension. Commented Aug 4, 2020 at 15:27

1 Answer 1

1

To share a database between an app and extension you need to fully implement Persistent History Tracking; it is not as simple as enabling the store option. For an introduction to the feature see WWDC 2017 What's New in Core Data at 20:49 and also see the documentation Consuming Relevant Store Changes in particular "Merge Relevant Transactions into a Context".

My theory on why you weren't noticing a problem when using the NSPersistentCloudKitContainer is when your store was online and syncing with the cloud is you were benefiting of a side effect of the cloud sync running in your app process and editing the store upon resuming which in turn caused your context to get updated.

And by the way, the NSPersistentHistoryTrackingKey option is set by default for NSPersistentCloudKitContainer's store descriptions that have cloudKitContainerOptions like the default first store description has.

Sign up to request clarification or add additional context in comments.

10 Comments

Did you mean the NSPersistentContainer?
Sorry I meant subclass NSPersistentCloudKitContainer
I have edited the question, and what I have tried so far.
Ok I have a new idea but first I'd like to know if you are using the history tracking feature that is necessary to share between app and extension.
Did anyone get this working without NSPersistentCloudKitContainer creating duplicates when two processes are trying to sync a common store?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.