First time SO user so excited to be here.
I've come up against a problem where I am trying to access my Core Data model in both main app and app extension, call directory. I've followed many online suggestions however none have seemed to work.
I've got the Call Directory Extension work and being able to reload from main app. Print in beginRequest confirms this.
I've then created a new Data model, CallerData with an entity Caller with a single attribute number.
I've also registered an app group in Apple developer and added the group in both targets. Everything is green.
I've then got my AppDelegate persistent container as:
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "CallerData")
let storeURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.io.project.ios.core.data")!.appendingPathComponent("CallerData.sqlite")
var defaultURL: URL?
if let storeDescription = container.persistentStoreDescriptions.first, let url = storeDescription.url {
defaultURL = FileManager.default.fileExists(atPath: url.path) ? url : nil
}
if defaultURL == nil {
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeURL)]
}
container.loadPersistentStores(completionHandler: { [unowned container] (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
if let url = defaultURL, url.absoluteString != storeURL.absoluteString {
let coordinator = container.persistentStoreCoordinator
if let oldStore = coordinator.persistentStore(for: url) {
do {
try coordinator.migratePersistentStore(oldStore, to: storeURL, options: nil, withType: NSSQLiteStoreType)
} catch {
print(error.localizedDescription)
}
// delete old store
let fileCoordinator = NSFileCoordinator(filePresenter: nil)
fileCoordinator.coordinate(writingItemAt: url, options: .forDeleting, error: nil, byAccessor: { url in
do {
try FileManager.default.removeItem(at: url)
} catch {
print(error.localizedDescription)
}
})
}
}
})
return container
}()
I've added Core Data to both targets and I've been able to successfully write and retrieve from the data store in my main app view controller using:
Save core data
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
let context = appDelegate.persistentContainer.viewContext
guard let entityDescription = NSEntityDescription.entity(forEntityName: "Caller", in: context) else { return }
let newValue = NSManagedObject(entity: entityDescription, insertInto: context)
newValue.setValue(number, forKey: "number")
do {
try context.save()
print("Saved \(number)")
} catch {
print("Saving error")
}
}
Retrieve
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
let context = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<Caller>(entityName: "Caller")
let numberSort = NSSortDescriptor(key:"number", ascending:true)
fetchRequest.sortDescriptors = [numberSort]
do {
let results = try context.fetch(fetchRequest)
for result in results {
print("Block core data result \(result.number)")
}
} catch {
print("Could not retrieve")
}
}
Now when I try to fetch the data from my app extension I get many errors. Below is the extension code and the errors.
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "CallerData")
let storeURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.io.project.core.data")!.appendingPathComponent("CallerData.sqlite")
var defaultURL: URL?
if let storeDescription = container.persistentStoreDescriptions.first, let url = storeDescription.url {
defaultURL = FileManager.default.fileExists(atPath: url.path) ? url : nil
}
if defaultURL == nil {
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeURL)]
}
container.loadPersistentStores(completionHandler: { [unowned container] (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
if let url = defaultURL, url.absoluteString != storeURL.absoluteString {
let coordinator = container.persistentStoreCoordinator
if let oldStore = coordinator.persistentStore(for: url) {
do {
try coordinator.migratePersistentStore(oldStore, to: storeURL, options: nil, withType: NSSQLiteStoreType)
} catch {
print(error.localizedDescription)
}
// delete old store
let fileCoordinator = NSFileCoordinator(filePresenter: nil)
fileCoordinator.coordinate(writingItemAt: url, options: .forDeleting, error: nil, byAccessor: { url in
do {
try FileManager.default.removeItem(at: url)
} catch {
print(error.localizedDescription)
}
})
}
}
})
return container
}()
let dataContext = persistentContainer.viewContext
let fetchRequest = NSFetchRequest<Caller>(entityName: "Caller")
let numberSort = NSSortDescriptor(key:"number", ascending:true)
fetchRequest.sortDescriptors = [numberSort]
do {
let results = try dataContext.fetch(fetchRequest)
for result in results {
print("Block core data result from Call Directory Extension \(result.number)")
}
} catch {
print("Could not retrieve")
}
[error] error: addPersistentStoreWithType:configuration:URL:options:error: returned error NSCocoaErrorDomain (256)
CoreData: annotation: NSSQLiteErrorDomain : 14
CoreData: annotation: storeType: SQLite
CoreData: annotation: configuration: PF_DEFAULT_CONFIGURATION_NAME
CoreData: annotation: URL: file:///private/var/mobile/Containers/Shared/AppGroup/70930707-4B5E-46E8-9083-C0D446A5568D/CallerData.sqlite/
CoreData: annotation: options:
CoreData: annotation: NSPersistentStoreRemoveUbiquitousMetadataOption : 1
The file “CallerData.sqlite” couldn’t be opened.
Any help is appreciated.
Thanks