我在应用程序中进行了手动逐步迁移,除了一些极少数情况下
replacePersistentStore(at destinationURL: URL...)
失败并出现错误:“Error Domain=NSSQLiteErrorDomain Code=5”(null)" UserInfo={NSFilePath=/private/ 时,它工作正常。 var/mobile/Containers/Shared/AppGroup/430DC264-B4D6-4853-A298-E989A5AC7E5E/MyApp/MyAppStorage.sqlite,源数据库路径=/private/var/mobile/Containers/Data/Application/73B79AA0-F609-4ABA-A864 -D9FFBC829393/tmp/E29D6F57-3BFB-46BD-A2AD-999907876BC6/MyAppStorage.sqlite,原因=无法替换目标数据库”。
我调查了这个问题并尝试重现它但无法重现。我仅在 Firebase Crashlytics 上看到这些崩溃。为了防止这个问题 - 在迁移完成之前我不会加载存储。 也许其他人也遇到过同样的问题或知道原因。 这是我的代码:
extension NSPersistentStoreCoordinator {
static func replaceStore(
at targetURL: URL,
withStoreAt sourceURL: URL,
options: [String: Any]
) {
do {
let persistentStoreCoordinator = NSPersistentStoreCoordinator(
managedObjectModel: NSManagedObjectModel()
)
try persistentStoreCoordinator.replacePersistentStore(
at: targetURL,
destinationOptions: options,
withPersistentStoreFrom: sourceURL,
sourceOptions: options,
ofType: NSSQLiteStoreType
)
} catch let error {
fatalError("failed to replace persistent store at \(targetURL) with \(sourceURL), error: \(error)")
}
}
...
func createTmpMigrationDirectory(url: URL) {
do {
try FileManager.default.createDirectory(
at: url,
withIntermediateDirectories: true,
attributes: nil
)
} catch {
Logger.logError("Failed to create directory at path: \(url), error: \(error)")
fatalError("failed to create directory at path: \(url), error: \(error)")
}
}
func removeTmpMigrationDirectory(url: URL) {
do {
try FileManager.default.removeItem(at: url)
} catch {
Logger.logError("Failed to remove item at path: \(url), error: \(error)")
}
}
...
func migration(
with step: CoreDataMigrationStep,
sourceURL: URL,
options: [String: Any]
) {
autoreleasepool {
let manager = NSMigrationManager(
sourceModel: step.source,
destinationModel: step.destination
)
let directoryURL = URL(
fileURLWithPath: NSTemporaryDirectory()
).appendingPathComponent(UUID().uuidString)
createTmpMigrationDirectory(url: directoryURL)
let destinationURL = directoryURL.appendingPathComponent(
sourceURL.lastPathComponent
)
do {
try manager.migrateStore(
from: sourceURL,
sourceType: NSSQLiteStoreType,
options: options,
with: step.mapping,
toDestinationURL: destinationURL,
destinationType: NSSQLiteStoreType,
destinationOptions: options
)
} catch {
fatalError("failed attempting to migrate from \(step.source) to \(step.destination), error: \(error)")
}
NSPersistentStoreCoordinator.replaceStore(
at: sourceURL,
withStoreAt: destinationURL,
options: options
)
removeTmpMigrationDirectory(url: directoryURL)
}
}
该代码没有任何明显的错误。
错误消息提到 SQLite 错误代码 5,这意味着 Core Data 出现 SQLITE_BUSY 错误。这表明替换调用失败,因为您正在尝试替换某处正在使用的持久存储。这可能在您的应用程序中,或者如果您有应用程序扩展,它可能位于其中之一中。
要追踪此情况,您需要找出发生情况的位置。在您的应用程序中,您需要确保您没有使用任何可以连接到您要替换的持久存储的东西。如果它是一个扩展,您需要以某种方式与其协调,以确保它不会妨碍。