Issue
This Content is from Stack Overflow. Question asked by ragavanmonke
I’m working on adding Widgetkit to my app to support some of the new iOS16 features (using Widgetkit for watch complications and lockscreen widgets), and step 1 of that process is converting my Cloudkit Core Data stack to support it. I’ve found a number of articles and threads about how it can be done, but I’m struggling with implementing the suggestions (I’m very new to SwiftUI). The format of these is different to my Core Data Stack, so I’m not sure what to amend to make this work.
Here’s my current CoreDataStack.swift
:
import SwiftUI
import CoreData
struct CoreDataStack {
static let shared = CoreDataStack()
var viewContext: NSManagedObjectContext {
return container.viewContext
}
init(inMemory: Bool = false) {
//
// The name of our container
//
container = NSPersistentCloudKitContainer(name: "PPBDataModel")
//
// Where our store lives
//
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
//
// If our container fails to load
//
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error (error), (error.userInfo)")
}
})
//
// Our Cloudkit merge policy
//
container.viewContext.automaticallyMergesChangesFromParent = true
}
let container: NSPersistentCloudKitContainer
// Saving
func saveContext() {
let context = container.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
fatalError("Error: (error.localizedDescription)")
}
}
}
}
The part I’m most stuck on, is where this bit goes:
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: <your_app_group>)!
let storeURL = containerURL.appendingPathComponent("DataModel.sqlite")
let description = NSPersistentStoreDescription(url: storeURL)
let container = NSPersistentContainer(name: "DataModel")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { ... }
And what within that needs to change in order to keep my Cloudkit setup working.
Any help with this would be tremendous.
Solution
First you need to create an AppGroup which will be used to create a Core Data Persistent Container (here is a good explanation how to do it)
Then you need to create your own CoreData stack (an example can be found when you create a new empty project with CoreData enabled).
Assuming you have already created your Core Data model (here called DataModel
), you now need to set the container url to your custom shared container location:
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: <your_app_group>)!
let storeURL = containerURL.appendingPathComponent("DataModel.sqlite")
let description = NSPersistentStoreDescription(url: storeURL)
let container = NSPersistentContainer(name: "DataModel")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { ... }
Now you can get the managedObjectContext
from your shared Persistent Container:
let moc = CoreDataStack.shared.managedObjectContext
and perform a fetch request with it (more information here)
let predicate = NSPredicate(format: "attribute1 == %@", "test")
let request = NSFetchRequest<SomeItem>(entityName: "SomeItem")
let result = try moc.fetch(request)
Apart from all the links above I recommend you also read this tutorial about Core Data:
Here is a GitHub repository with different Widget examples including the Core Data Widget.
This Question was asked in StackOverflow by umayanga and Answered by pawello2222 It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.