Core Data直读App Bundle只读数据库:同配置容器单库真机崩溃问题
只读Core Data直接读取Bundle路径的真机崩溃问题
基础场景
- 存在两个随App新版本不定期更新的只读SQLite数据库
- 不采用将Bundle内SQLite文件拷贝到Documents目录完成版本更新的方案,直接将持久化容器指向App Bundle路径读取数据库内容
- 运行表现对比:
- 其中一个数据库全平台运行正常
- 另一个数据库在模拟器下可正常运行,真机上触发崩溃
- 两个数据库使用完全一致的持久化容器初始化配置逻辑
实现代码对比
无崩溃的持久化容器配置
该数据库后续通过FetchedResultsController执行查询操作,配置代码如下:
lazy var strengthPersistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "Favs") let sqlFileName: String = kStrengthShortFileName let sqlFileExtension: String = "sqlite" let fileUrl: URL = Bundle.main.url(forResource: sqlFileName, withExtension: sqlFileExtension)! let description = NSPersistentStoreDescription(url: fileUrl) description.isReadOnly = true container.persistentStoreDescriptions = [description] container.loadPersistentStores { _, error in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } } return container }()
崩溃的持久化容器配置
该数据库后续通过单例封装的上下文执行普通fetch查询,配置逻辑与前者完全一致,代码如下:
lazy var everKeneticPersistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "EverKenetic") let sqlFileName: String = kEverKineticFileName let sqlFileExtension: String = "sqlite" let fileUrl: URL = Bundle.main.url(forResource: sqlFileName, withExtension: sqlFileExtension)! let description = NSPersistentStoreDescription(url: fileUrl) description.isReadOnly = true container.persistentStoreDescriptions = [description] container.loadPersistentStores { _, error in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } } return container }()
崩溃触发的查询逻辑
单例封装的查询代码如下,崩溃位置位于context.fetch(fetchRequest)调用处:
class EverKenetic: NSObject { private static var manager: EverKenetic = EverKenetic() var everKineticContext: NSManagedObjectContext? override init() { if let appDelegate = UIApplication.shared.delegate as? AppDelegate { let theContext = appDelegate.everKeneticPersistentContainer.viewContext everKineticContext = theContext } } class func exerciseInfo(_ everKeneticName: String) -> EverKeneticExercise! { let fetchRequest: NSFetchRequest<EverKeneticExercise> = EverKeneticExercise.fetchRequest() if let context: NSManagedObjectContext = manager.everKineticContext { let entity = NSEntityDescription.entity(forEntityName: "EverKeneticExercise", in: context) fetchRequest.entity = entity fetchRequest.fetchBatchSize = 2 let predicate: NSPredicate = NSPredicate(format: "name = %@", everKeneticName) fetchRequest.predicate = predicate let sortDescriptorRoutine = NSSortDescriptor(key: "name", ascending: false) fetchRequest.sortDescriptors = [sortDescriptorRoutine] fetchRequest.returnsObjectsAsFaults = false var fetch: [EverKeneticExercise]? do { fetch = try context.fetch(fetchRequest) } catch _ as NSError { fetch = nil } if let result = fetch, !result.isEmpty { return result[0] } } return nil } }
崩溃详情
- 抛出异常类型:未捕获的
NSInternalInconsistencyException - 核心错误信息:
Can't create support directory (can't create directory) - 最终结果:程序因NSException类型异常终止
诉求
目前直接读取App Bundle内只读Core Data数据库的可参考实现较少,需要对应问题的排查方向和可落地的实现指导。
内容的提问来源于stack exchange,提问作者Greg Robertson
相关产品推荐
相关产品推荐

