使用NSReadOnlyPersistentStoreOption时崩溃

时间:2014-03-22 18:53:25

标签: sqlite core-data ios7

我在我的应用程序中使用位于MainBundle的只读sqlite数据库。在PersistentStoreCoordinator中,我使用以下代码加载数据库:

    NSDictionary *storeOptions = @{NSReadOnlyPersistentStoreOption : [NSNumber numberWithBool:YES]};

NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self applicationManagedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[[NSBundle mainBundle] URLForResource:@"applications" withExtension:@"sqlite"] options:nil error:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error description]);
    abort();
}

在iOS7中,此代码在模拟器和设备中崩溃,并出现以下错误:

 CoreData: error: (14) I/O error for database at /var/mobile/Applications/4B81AEFE-03E6-4156-B52D-3452515FACAF/myapp.app/applications.sqlite.  SQLite error code:14, 'unable to open database file'
2014-03-22 20:45:34.346 GfxHotkeys3[1369:60b] CoreData: error: Encountered exception I/O error for database at /var/mobile/Applications/4B81AEFE-03E6-4156-B52D-3452515FACAF/myapp.app/applications.sqlite.  SQLite error code:14, 'unable to open database file' with userInfo {
    NSFilePath = "/var/mobile/Applications/4B81AEFE-03E6-4156-B52D-3452515FACAF/myapp.app/applications.sqlite";
    NSSQLiteErrorDomain = 14;
} while checking table name from store: <NSSQLiteConnection: 0x155b0fd0>
2014-03-22 20:45:34.372 GfxHotkeys3[1369:60b] Unresolved error Error Domain=NSCocoaErrorDomain Code=256 "The operation couldn’t be completed. (Cocoa error 256.)" UserInfo=0x155b01b0 {NSUnderlyingException=I/O error for database at /var/mobile/Applications/4B81AEFE-03E6-4156-B52D-3452515FACAF/myapp.app/applications.sqlite.  SQLite error code:14, 'unable to open database file', NSSQLiteErrorDomain=14}, Error Domain=NSCocoaErrorDomain Code=256 "The operation couldn’t be completed. (Cocoa error 256.)" UserInfo=0x155b01b0 {NSUnderlyingException=I/O error for database at /var/mobile/Applications/4B81AEFE-03E6-4156-B52D-3452515FACAF/GfxHotkeys3.app/applications.sqlite.  SQLite error code:14, 'unable to open database file', NSSQLiteErrorDomain=14}

在商店选项中传递nil,将在模拟器中运行应用程序但不在设备上运行(因为它无法在MainBundle上写入)。

我可以通过将数据库复制到文档并从那里加载来解决这个问题,但我想知道为什么会发生这种情况。我现在使用这个选项多年来从MainBundle加载只读sqlite,但是在iOS 7中崩溃......

任何线索?

非常感谢

4 个答案:

答案 0 :(得分:3)

问题是原始文件是使用WAL选项创建的(现在是OS X Mavericks和iOS 7上的默认选项)。为了能够使用NSReadOnlyPersistentStoreOption,您需要创建一个关闭WAL的文件。您需要将此指令添加到iOS项目中:

NSDictionary *storeOptions = @{NSReadOnlyPersistentStoreOption : [NSNumber numberWithBool:YES], NSSQLitePragmasOption : @{@"journal_mode" : @"DELETE"}}

以及使用创建原始文件的项目。 E.I.将您的数据重新导入到使用以下设置的NSSQLitePragmasOption创建的NSPersistantStore文件中:

NSDictionary *storeOptions = @{NSSQLitePragmasOption : @{@"journal_mode" : @"DELETE"}};

我认为这是实现中的一个错误,因为没有技术原因导致此错误,因为Core Data处理使用WAL创建的文件上的元数据的方式,文件不会被加载。

答案 1 :(得分:2)

要打开只读存储,您应该使用

NSDictionary *storeOptions = @{NSReadOnlyPersistentStoreOption : @YES};

而不是@NO

答案 2 :(得分:2)

我认为您可以通过先将商店复制到文档目录来轻松解决问题。然后你可以传递只读选项(没关系,你可以不写它)。

至少这可能是一个很好的测试,看看你是否可以隔离这个问题..

我认为崩溃的原因可能是因为新版本的SQLite在访问商店时会创建另外两个文件。因为捆绑不可写,所以你会崩溃。

答案 3 :(得分:0)

在swift 3.0中,使用以下内容初始化持久性存储协调器:

fileprivate lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
    var coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)

    let bundlePath = Bundle.main.path(forResource: "TrackWaypoints", ofType: ".sqlite")
    let bundleURL = URL(fileURLWithPath: bundlePath!)

    let hi = [NSReadOnlyPersistentStoreOption:true, NSSQLitePragmasOption: ["journal_mode": "delete"]] as [String: Any]
    let store = try! coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: bundleURL, options: hi)
    return coordinator
}()