Issue #938
To let app and extension to talk to the same database, we need to use AppGroup
. Here is how to use replacePersistentStore
Replaces one persistent store with another
actor DatabaseMigrator {
@AppStorage("DatabaseMigrator.hasMigrated") var hasMigrated = false
func migrateIfNeeded() {
guard
!hasMigrated
else { return }
migrate()
hasMigrated = true
}
private func migrate() {
let oldContainer = NSPersistentCloudKitContainer(name: "Bookmarks")
guard
let oldStoreUrl = oldContainer.persistentStoreDescriptions.first?.url,
let newStoreUrl = Constants.appGroup.folderUrl?.appendingPathComponent(oldContainer.name + ".sqlite"),
FileManager.default.fileExists(atPath: oldStoreUrl.path),
!FileManager.default.fileExists(atPath: newStoreUrl.path)
else { return }
let coordinator = oldContainer.persistentStoreCoordinator
do {
try coordinator.replacePersistentStore(
at: newStoreUrl,
withPersistentStoreFrom: oldStoreUrl,
type: .sqlite
)
try coordinator.destroyPersistentStore(at: oldStoreUrl, type: .sqlite)
} catch {
print(error)
}
}
}
There is a note on migratePersistentStore
vs replacePersistentStore
from Core Data WWDC 2020 FAQ
Additionally you should almost never use NSPersistentStoreCoordinator’s migratePersistentStore… method but instead use the newer replacePersistentStoreAtURL.. (you can replace emptiness to make a copy). The former loads the store into memory so you can do fairly radical things like write it out as a different store type. It pre-dates iOS. The latter will perform an APFS clone where possible.