如何用应用商店中的新版本替换 iOS 应用中预先填充的核心数据?

Posted

技术标签:

【中文标题】如何用应用商店中的新版本替换 iOS 应用中预先填充的核心数据?【英文标题】:How to replace pre-populated core data in iOS app with new version from the app store? 【发布时间】:2016-01-03 11:36:31 【问题描述】:

我将预加载的核心数据作为 3 个捆绑文件(.sqlite、.sqlite-shm、.sqlite-wal)包含在我的应用中,并在用户下载应用时将它们用作主要核心数据。

这就是我在 AppDelegate.swift 中的内容

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = 
    // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
    // Create the coordinator and store
    var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
    let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("coreDB.sqlite")




    /******************** If core data is empty, import from the bundle *******************/
    if !NSFileManager.defaultManager().fileExistsAtPath(url.path!) 
        let sourceSqliteURLs = [NSBundle.mainBundle().URLForResource("coreDB", withExtension: "sqlite")!, NSBundle.mainBundle().URLForResource("coreDB", withExtension: "sqlite-wal")!, NSBundle.mainBundle().URLForResource("coreDB", withExtension: "sqlite-shm")!]

        let destSqliteURLs = [self.applicationDocumentsDirectory.URLByAppendingPathComponent("coreDB.sqlite"),
            self.applicationDocumentsDirectory.URLByAppendingPathComponent("coreDB.sqlite-wal"),
            self.applicationDocumentsDirectory.URLByAppendingPathComponent("coreDB.sqlite-shm")]

        var error:NSError? = nil
        for var index = 0; index < sourceSqliteURLs.count; index++ 
            do 
                try NSFileManager.defaultManager().copyItemAtURL(sourceSqliteURLs[index], toURL: destSqliteURLs[index])
             catch var error1 as NSError 
                error = error1
             catch 
                fatalError()
            
        
    


var error: NSError? = nil
    var failureReason = "There was an error creating or loading the application's saved data."
    do 
        try coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true])
     catch var error1 as NSError 
        error = error1
        coordinator = nil
        // Report any error we got.
        var dict = [String: AnyObject]()
        dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
        dict[NSLocalizedFailureReasonErrorKey] = failureReason
        dict[NSUnderlyingErrorKey] = error
        error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog("Unresolved error \(error), \(error!.userInfo)")
        //abort()
     catch 
        fatalError()
    

    return coordinator
()

现在我不得不从核心数据中更改一些数据,所以这就是我所做的:

1) 使用 xcode 更改核心数据中的一些数据,以便在 ios 模拟器中运行应用程序时更改数据

2) 找到属于iOS模拟器的.sqlite、.sqlite-shm、sqlite-wal文件

3) 将这 3 个文件拖入 xcode 并将它们包含在应用程序的 bundle 中

4)当用户更新应用程序时,如何使新更新的应用程序用这3个文件替换其核心数据?所谓的 Lightmigration 是解决此类问题的方法吗?

【问题讨论】:

【参考方案1】:

我在我的一个应用程序中做同样的事情,所有与 sqlite 相关的文件都与应用程序捆绑在一起,在第一次启动时,我将它们复制到一个目录中,该目录由使用应用程序版本号组成。

- (NSString *)applicationDatabaseDirectory

    NSString * documentsDir = [self applicationDocumentsDirectory];
    NSString * databasePath = [documentsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"Database/%@",[self appVersionString]]];
    NSFileManager * fileManager = [[NSFileManager alloc] init];
    BOOL isDir = YES;
    if (![fileManager fileExistsAtPath:databasePath isDirectory:&isDir]) 
        [fileManager createDirectoryAtPath:databasePath withIntermediateDirectories:YES attributes:nil error:nil];
    
    return databasePath;

- (NSString *) appVersionString 
    return  [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];

请记住,每次向模型添加一些新属性时,都必须使用迁移更新捆绑包中的数据库并再次复制文件,删除旧文件。

【讨论】:

以上是关于如何用应用商店中的新版本替换 iOS 应用中预先填充的核心数据?的主要内容,如果未能解决你的问题,请参考以下文章

iOS 应用程序在更新到新版本和新的 firebasedb 后崩溃

在完全不同的配置文件下向应用商店发布新版本

在 iTunes 中发布更新版本的应用程序

从 Xcode 中的应用商店复制 iOS 应用更新过程

Android 应用在 Play 商店中显示新版本,但下载旧 APK

为已发布的应用程序 iOS 上传新版本?