2

我正在使用 Main Bundle 中的只读 Core Data sqlite,效果很好。当我将新版本的数据库(更多只读数据)添加到主包时,它仍然会读取数据库的“旧”版本。

当当前用户使用新版本的数据库下载更新时,任何人都可以帮助我理解为什么以及如何使新数据库版本成为当前版本?

这是试图解决这篇文章中的问题的一部分:从文档目录访问更新的数据库时出现同样的问题

===解决方案====

我通过在“新”主包中更改新数据库的名称解决了这个问题,它就像一个梦一样工作。此外,如果这是更新,我会删除文档目录中的旧数据库以进行清理。

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    if (persistentStoreCoordinator != nil) {
    return persistentStoreCoordinator;
}


//===READ DATABASE FROM MAIN BUNDLE===//
NSFileManager *fileManager = [NSFileManager defaultManager];

NSURL *storeUrl = [[NSBundle mainBundle] URLForResource:kNewDB withExtension:@"sqlite"];

//=== IF THE OLD DATABASE STILL EXIST DELETE IT FROM DOCUMENT DIRECTORY ===//
NSURL *oldDatabasePathURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"database.sqlite"];
NSString *oldDatabasePath = [oldDatabasePathURL path];
if ([fileManager fileExistsAtPath:oldDatabasePath]) {
    //Remove old database from Documents Directory
    [fileManager removeItemAtURL:oldDatabasePathURL error:nil];

}

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 

persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

NSError *error;
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
    // Update to handle the error appropriately.
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    exit(-1);  // Fail
}    

return persistentStoreCoordinator;
}
4

2 回答 2

2

您必须在代码中有一个位置,您可以检查数据库文件的副本是否存在于某个可写目录(可能是您的 Documents 目录)中,如果不存在,则将其复制到那里。当您需要对数据库进行更改时,这是一种非常常见的方法。问题是,当您更新应用程序时,该文件已经存在,因此永远不会再次复制。

有两种方法可以解决您的问题:

  1. (首选):一开始就不要复制数据库。由于它是只读的,因此您不需要,它只会占用设备上的额外空间。只需使用主包中的文件路径打开数据库。

  2. 与其检查文件是否存在于可写目录中,不如检查它是否比主包中的文件新。(不要使用日期,因为他们可能已经安装了程序并在您的更新提交到应用商店以供批准后创建了文件,这将导致无法复制新的。您需要检查版本数据库,可能通过在您的应用程序包中存储另一个文件来存储版本信息,或使用特定于版本的代码来确定它)。如果没有,那就再复制一遍。

于 2012-07-15T14:10:08.697 回答
1

PeterK,我在使用http://www.raywenderlich.com/12170/core-data-tutorial-how-to-preloadimport-existing-data-updated上的教程以使用只读 sqlite 数据库时遇到了同样的问题由核心数据。一切都很好,直到我不得不更新我的数据库并重新发布我的目标应用程序。如您所知,该教程中建议的代码仅在应用程序的 Documents 目录中不存在数据库时复制到新数据库中。

我不认为重命名我的数据库(并更新复制代码)是一种好的设计方法,所以我按照 Inafziger 的首选建议和阅读 iOS 文件结构来完成我的设计。我提供以下内容只是为了展示如何实施 Inafziger 的提议。值得注意的是,这种方法可能仅在您的应用程序不更改核心数据信息的内容时才有效,因为它以只读方式读入。

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
  if (_persistentStoreCoordinator != nil) {
    return _persistentStoreCoordinator;
  }    

  // Updated processing to now just have the NRPersistentStoreCoordinator point to the sqlite db in the
  //           application's Bundle and not by copying that db to the app's Documents directory and then using
  //           the db in the Documents directory.
  NSURL *refactoredStoreURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@“NameOfYourDatabase ofType:@"sqlite"]];


  NSError *error = nil;

  _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

  // Added to ensure the NSPersistentStoreCoordinator reads the Bundle's db file as read-only since
    //           it is not appropriate to allow the app to modify anything in the Bundle
  NSDictionary *readOnlyOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSReadOnlyPersistentStoreOption, nil];

  // Use the URL that points to the Bundle's db file and used the ReadOnly options
  if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:refactoredStoreURL options:readOnlyOptions error:&error]) {
    // Your logic if there is an error
  }
  return _persistentStoreCoordinator;
}   

我希望这对这个问题的下一位读者有所帮助。

于 2014-01-01T11:37:20.797 回答