应用程序包中包含的核心数据存储

10

我在苹果文档中找不到这些步骤的清晰描述...

  1. 我在我的Xcode项目中有一个xcdatamodeld
  2. 在启动时,我的应用程序解析一个XML(项目资源)以填充Core Data Store(SQLLite)
  3. 在我的应用程序生命周期内,我添加,删除,更新该存储的数据

现在,我想停止在设备上进行繁重的XML解析过程,并直接包含一个包含所需数据的存储。

我有一些关于此的问题:

  • 我能否使用OS X应用程序填充存储并将此存储包含在我的XCode-iOs项目中?
  • 我的存储在Xcode中没有显示。实际上它是在运行时创建的。如何在项目中添加存储并将其链接到我的xcdatamodeld?
  • 我已经阅读了这样做会防止我的存储可写...我想我必须在启动时将它复制到正确的位置(Core Data实用程序教程对此非常有帮助)。我是对的吗?

感谢您的提示。URL或其他SO问题将非常感激!

Kheraud

4个回答

16

你可以将存储文件(大多数情况下是sqlite数据库)包含在你的应用程序中。 然后在你的应用程序委托中编辑persistentStoreCoordinator getter方法:


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

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

    NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"CoreDataStore.sqlite"];

    // Check if the store exists in. 
    if (![[NSFileManager defaultManager] fileExistsAtPath:storePath]) {
        // copy the payload to the store location.
        NSString *bundleStore = [[NSBundle mainBundle] pathForResource:@"YourPayload" ofType:@"sqlite"];

        NSError *error = nil;
        [[NSFileManager defaultManager] copyItemAtPath:bundleStore toPath:storePath error:&error];

        if (error){
            NSLog(@"Error copying payload: %@", error);
        }
    }

    NSError *error = nil;
    NSURL *storeURL = [NSURL fileURLWithPath:storePath];
    persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return persistentStoreCoordinator_;
}

感谢提供这段代码。你不觉得设备、Core Data和复制的数据库之间可能存在兼容性问题吗? - kheraud
不,我大多数情况下使用模拟器创建数据库,然后在设备上使用它,没有问题。 - rckoenes
在你的回答的第二个句子中,“persantstore”是什么?(打错字了吗?) - David

11
  1. 使用应用程序的数据模型和类编写一个实用工具应用程序。使用该实用工具应用程序从XML提供的数据生成持久性存储。
  2. 像任何其他资源一样将存储文件添加到应用程序包中。
  3. 在应用程序目录中选择要放置活动存储的位置,例如Library目录。
  4. 启动时,应用程序应检查目录中是否存在存储。如果不存在,则应用程序应使用标准NSFileManger方法将存储从应用程序包复制到目录中,就像处理任何其他文件一样。(通常,只需要在创建存储的第一次执行此操作。)

实际上就是这么简单。


2
我把 SQLite 文件放在 Bundle 里面,因为它是只读的,这样可以吗? - onmyway133
Core Data 会在应用程序的应用程序支持目录中查找 sqlite 文件:try FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: false) 是一种获取此文件的方法。如果您要预加载数据库,则可以将文件的副本保留在捆绑包中,以便复制到应用程序支持中。-- 哎呀,这当然是 Swift,因为已经过了几年啦 ;-) - leanne

8
您目前正在进行的操作(首次启动时填充)是填充Core Data存储库的“推荐”方式。尽管有些hackish,但是您可以按照以下步骤为设备上的数据库添加数据:
  1. 在模拟器中启动您的应用程序
  2. 执行所需的操作以填充Core Data存储库
  3. 停止模拟器应用程序
  4. 导航到模拟Documents文件夹(类似 ~/Library/Application Support/iPhone Simulator/4.3/Applications/335567A0-760D-48AF-BC05-7F0D9BD085B6/<app-name>.app/)
  5. 找到sqlite数据库(它的名称与初始化Core Data时给出的名称相同)
  6. 将此数据库复制到您的项目中,并将其添加为要复制的资源
  7. 添加一些代码到您的application:didFinishLaunchingWithOptions:方法中,以便在第一次启动时,将数据库从只读资源目录复制到应用程序的文档目录中。当然,在初始化Core Data之前,您需要这样做。
根据您在数据库中存储的内容,您可能会发现大端与小端问题或其他不兼容性。为了使这种方法更加安全,您可以在Mac上转储模拟器数据库(splite3 databasefile .dump >dumpfile),然后在您的项目中包含转储文件(如上所述),并在首次启动应用程序时将其读入应用程序中(逐行读取它,并将SQL语句传递给sqlite API)。

好的。看起来使用SQL转储和解析+填充是一个不错的方法。但处理XML并不那么复杂(我认为)。此外,我通过网络接收XML数据并需要解析它。我将保持我的XML机制不变...感谢您的帮助,我以后可能会用到它 :) - kheraud

0

针对更新的Swift 5答案,按照上述主题执行以下操作:

  1. 从其他地方将数据填充到核心数据SQLite数据库中。
  2. 将创建的数据库包含在您的应用程序包中。
  3. 在应用程序启动时检查该文件是否在“应用程序支持”文件夹中,如果不在,则将种子数据库移动到那里。

这是相关的Swift代码,我将我的代码放在持久性控制器共享实例的静态初始化器中,但您可以根据需要进行更改。

   static func seedDataIfRequired() {
    let dbname = "your file name here"
    if let appSupportDirURL : URL = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
        let appSupportDir = appSupportDirURL.path(percentEncoded:false)
        if FileManager.default.fileExists(atPath: "\(appSupportDir)\(dbname).sqlite") {
            debugPrint("Core data database exists, no action needed.")
        }else {
            if let seedDatabasePath = Bundle.main.path(forResource: "\(dbname)", ofType: "sqlite") {
                debugPrint("Seed database is available.")
                // move it there
                try? FileManager.default.createDirectory(atPath: appSupportDir, withIntermediateDirectories: true)
                let status = FileManager.default.secureCopyItem(at:URL(filePath: seedDatabasePath) , to: URL(filePath: "\(appSupportDir)\(dbname)"))
                if status == true {
                    debugPrint("Seed database COPIED.")
                }else{
                    debugPrint("Seed database copy FAILURE.")
                }
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接