Swift 3 核心数据问题 - 所有数据丢失

Posted

技术标签:

【中文标题】Swift 3 核心数据问题 - 所有数据丢失【英文标题】:Swift 3 Core Data issue - All Data Missing 【发布时间】:2016-12-22 06:24:35 【问题描述】:

我将我的 Core Data 项目从 Swift 2 升级到 Swift 3。将 Core Data 堆栈替换为 NSPersistentContainer。但是新版本找不到旧数据了。

安装新版本后:

Swift 3 版本应用找不到任何数据

我的应用程序的功能是记录单词/句子及其中文含义。如果我在App Store上发布此版本,用户将在更新后丢失所有记录。

我该如何解决这个问题?

这是我的 Swift 3 代码:

// MARK: - Core Data stack

lazy var applicationDocumentsDirectory: URL = 
    // The directory the application uses to store the Core Data store file. This code uses a directory named "social.street.NewWords" in the application's documents Application Support directory.
    let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return urls[urls.count-1]
()

lazy var persistentContainer: NSPersistentContainer = 
    let modelURL = Bundle.main.url(forResource: "NewWords", withExtension: "momd")!
    let container = NSPersistentContainer(name: "NewWords", managedObjectModel: NSManagedObjectModel(contentsOf: modelURL)!)

    let documentsDirectory = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask)

    let storeUrl = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")

    print(storeUrl)

    container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeUrl)]

    container.loadPersistentStores(completionHandler:  (storeDescription, error) in
        if let error = error as? NSError 
            fatalError("Unresolved error \(error), \(error.userInfo)")
        
    )
    return container
()

Swift 2 代码:

// MARK: - Core Data stack

lazy var applicationDocumentsDirectory: NSURL = 
    // The directory the application uses to store the Core Data store file. This code uses a directory named "social.street.NewWords" in the application's documents Application Support directory.
    let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
    return urls[urls.count-1]
()

lazy var managedObjectModel: NSManagedObjectModel = 
    // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
    let modelURL = NSBundle.mainBundle().URLForResource("NewWords", withExtension: "momd")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
()

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = 
    // The persistent store coordinator for the application. This implementation creates and returns 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
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
    let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
    var failureReason = "There was an error creating or loading the application's saved data."
    do 
        try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
     catch 
        // 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 as NSError
        let wrappedError = 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 \(wrappedError), \(wrappedError.userInfo)")
        abort()
    

    return coordinator
()

lazy var managedObjectContext: NSManagedObjectContext = 
    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
    let coordinator = self.persistentStoreCoordinator
    var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = coordinator
    return managedObjectContext
()

代码升级到 Swift 3 后如何保留数据?

另外:swift 2 版本是从 App Store 安装的,swift 3 版本是从 Xcode 安装的。

Project's Github repo

【问题讨论】:

你记录了modelURL、container、storeUrl等吗?它们是否与 Swift 2 版本保持一致? 我找不到 Swift 2 版本的日志。但是如你所见,我的modelURL,storeUrl的代码和之前的版本是一样的。 您实施了轻量级迁移吗?我相信这应该可以解决问题,如果您将属性从一个版本添加/删除/更改到应用程序的下一个版本,您必须实施轻量级迁移,以便该应用程序可以修改数据库而不是替换 【参考方案1】:

您是否实施了轻量级迁移?

当您初始化持久存储时,您可以添加“选项”,以实现轻量级迁移添加:

let options = [NSMigratePersistentStoresAutomaticallyOption: true,
                     NSInferMappingModelAutomaticallyOption: true]

然后,当您首先更改每个应用版本的数据库时,您必须转到 .xcdatamodel 并转到:

'editor' > 'Add Model Version' 

然后在顶部菜单中对此版本进行更改,并确保在打开模型时它有绿色勾号。

【讨论】:

我使用let storeOptions: [String:Any] = [NSPersistentStoreUbiquitousContentNameKey:"CloudNewWordsStore",NSMigratePersistentStoresAutomaticallyOption:true, NSInferMappingModelAutomaticallyOption:true]。有效!谢谢,你救了我。 很高兴能提供一些帮助:D

以上是关于Swift 3 核心数据问题 - 所有数据丢失的主要内容,如果未能解决你的问题,请参考以下文章

快速的核心数据。应用程序丢失数据?

Bundle Identifier Changed 核心数据丢失

如何使用 swift 3 在核心数据中搜索字符串?

如何在核心数据swift 3中同时保存和获取

删除核心数据swift3中每个实体中的所有数据

swift - 当persistentContainer不在App委托方法中时如何从核心数据中删除所有数据