CoreData loadPersistentStores无回调致App白屏启动失败求助
问题:CoreData新增备份功能后启动无
loadPersistentStores回调导致白屏 近几周为CoreData新增了数据库备份功能,上线后收到用户反馈App启动时白屏无法正常运行。经排查,问题根源是loadPersistentStores执行后无回调。此前从未出现该问题,因此怀疑与新增的备份功能相关。
备份功能代码
func backupSync(completionBlock: @escaping ((Bool) -> Void) = { _ in }) { do { let backupDir = self.createFolder(name: self.backupFolderName, baseUrl: self.getDocumentsDirectory()) let backupTime = "backup_\(Date().timeIntervalSince1970)" let backupFile = try CoreDataStack.shared.backup(fileName: backupTime) let backupPath = backupDir + "/" + backupFile.lastPathComponent // copy file if !FileManager.default.fileExists(atPath: backupPath) { try FileManager.default.copyItem(at: backupFile, to: URL(fileURLWithPath: backupPath)) } // zip files with password let zipPath = backupDir + "/\(backupTime).zip" SSZipArchive.createZipFile(atPath: zipPath, withFilesAtPaths: [backupPath], withPassword: self.password) // delete copy file if FileManager.default.fileExists(atPath: backupPath) { try FileManager.default.removeItem(at: URL(fileURLWithPath: backupPath)) } "\(zipPath)".debugLog("Local backup") completionBlock(true) } catch { completionBlock(false) print(error) } } func backup(fileName: String) throws -> URL { let backupfile = try persistentContainer.persistentStoreCoordinator.backupPersistentStore(atIndex: 0, fileName: fileName).fileURL return backupfile } func backupPersistentStore(atIndex index: Int, fileName: String) throws -> TemporaryFile { precondition(persistentStores.indices.contains(index), "Index \(index) doesn't exist in persistentStores array") let sourceStore = persistentStores[index] let backupCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel) let intermediateStoreOptions = (sourceStore.options ?? [:]) .merging([NSReadOnlyPersistentStoreOption: true], uniquingKeysWith: { $1 }) let intermediateStore = try backupCoordinator.addPersistentStore( ofType: sourceStore.type, configurationName: sourceStore.configurationName, at: sourceStore.url, options: intermediateStoreOptions ) let backupStoreOptions: [AnyHashable: Any] = [ NSReadOnlyPersistentStoreOption: true, NSSQLitePragmasOption: ["journal_mode": "DELETE"], // Minimize file size NSSQLiteManualVacuumOption: true, ] let backupFilename = fileName + ".sqlite" let backupFile = try TemporaryFile(creatingTempDirectoryForFilename: backupFilename) try backupCoordinator.migratePersistentStore(intermediateStore, to: backupFile.fileURL, options: backupStoreOptions, withType: NSSQLiteStoreType) return backupFile }
备份触发时机
场景1:sceneDidEnterBackground中通过Operation结合UIApplication.shared.beginBackgroundTask执行
class BackUpOpeartion: Operation { override func main() { LocalBackupManager.shared.backupSync() } static func canHandler() -> Bool { let backupStrategy = LocalUserDefaults.standard.backupUiModel let lastBackUpDate = LocalUserDefaults.standard.lastBackUpDate let now = Date() let sixHour: TimeInterval #if DEBUG sixHour = TimeInterval(0.15 * 60 * 60) #else sixHour = TimeInterval(backupStrategy.backupFrequency) // 6h #endif let backupDate = lastBackUpDate + sixHour // Clean the database at most once per week. guard now > backupDate else { "It's not time to backup".debugLog() return false } return true } static func doWhenEnterBackground() { if !canHandler() { return } var bgtToken = UIBackgroundTaskIdentifier.invalid bgtToken = UIApplication.shared.beginBackgroundTask(expirationHandler: { UIApplication.shared.endBackgroundTask(bgtToken) }) guard bgtToken != .invalid else{ return } DispatchQueue.global(qos: .utility).async { LocalBackupManager.shared.backupSync { succeed in DispatchQueue.main.async { if succeed { LocalUserDefaults.standard.lastBackUpDate = Date() } UIApplication.shared.endBackgroundTask(bgtToken) } } } } }
场景2:AppDelegate中的BGProcessingTask
func registerBackgroundTasks() { BGTaskScheduler.shared.register(forTaskWithIdentifier: dbBackupId, using: nil) { task in self.backupDb(task: task as! BGProcessingTask) } } func scheduleDbBackup() { if !BackUpOpeartion.canHandler() { return } let request = BGProcessingTaskRequest(identifier: dbBackupId) request.requiresNetworkConnectivity = false request.requiresExternalPower = false do { try BGTaskScheduler.shared.submit(request) "submit DbBackup".debugLog() } catch { print("Could not schedule app refresh: \(error)") } } func backupDb(task: BGProcessingTask) { let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 let operation = BackUpOpeartion() task.expirationHandler = { queue.cancelAllOperations() } operation.completionBlock = { let success = !operation.isCancelled if success { LocalUserDefaults.standard.lastBackUpDate = Date() } task.setTaskCompleted(success: success) } }
不清楚在何种情况下会导致CoreDataStack的loadPersistentStores无回调,恳请各位帮忙分析原因,谢谢!
内容的提问来源于stack exchange,提问作者wanbo
相关产品推荐
相关产品推荐

