iOS:当我从前台切换到后台时,我丢失了核心数据实体。

3

我正在使用Swift构建一个iPad应用程序,但我无法弄清楚如何在前台和后台切换时保留我的实体。 如果我关闭应用程序(从任务管理器中),所有实体都会再次出现。 我正在使用Apple提供的标准Core Data堆栈。 如果我使用iCloud,这种情况就不会发生。

有任何想法吗? 我爬过StackOverflow,但找不到任何东西。 谢谢。

编辑:

App Delegate

// 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 "it.b3lab.ProjectIceCream" in the application's documents Application Support directory.
    let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
    return urls[urls.count-1] as NSURL
}()

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("ProjectIceCream", withExtension: "momd")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

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)
    //Add support to ligtweight migrations, and iCloud persistent storage
    var options = [
        NSMigratePersistentStoresAutomaticallyOption: true,
        NSInferMappingModelAutomaticallyOption: true,
        NSPersistentStoreUbiquitousContentNameKey: "ProjectIceCreamCloudStore"
    ]

    //enabled iCloud notiiccation subscription
    var notification = NSNotificationCenter.defaultCenter()
    notification.addObserver(self, selector: "storeDidChangeNotification:",
        name: NSPersistentStoreCoordinatorStoresDidChangeNotification,
        object:nil)
    notification.addObserver(self, selector: "storeWillChangeNotification:",
        name: NSPersistentStoreCoordinatorStoresWillChangeNotification,
        object:nil)
    notification.addObserver(self, selector: "storeDidImportUbiquitousContent:",
        name: NSPersistentStoreDidImportUbiquitousContentChangesNotification,
        object:nil)

    let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("ProjectIceCream.sqlite")
    var error: NSError? = nil
    var failureReason = "There was an error creating or loading the application's saved data."

    if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType,
        configuration: nil, URL: url, options:options, error: &error) == nil {
        coordinator = nil

        // Report any error we got.
        let dict = NSMutableDictionary()
        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()
    }

    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
    if coordinator == nil {
        return nil
    }
    var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = coordinator
    return managedObjectContext
}()


//MARK: iCloud notification methods
func storeDidChangeNotification(notification: NSNotification) {
    println("Core Data successfully created and configured an iCloud-enabled persistent store")
    //TODO: controllare che i dati in ingresso siano validi
    //TODO: Implement Refresh your User Interface.
}

func storeWillChangeNotification(notification: NSNotification) {
    println("Called storeWillChangeNotification")
    var moc: NSManagedObjectContext = self.managedObjectContext!
    moc.performBlock { () -> Void in
        if moc.hasChanges {
            var saveError: NSError?
            if moc.save(&saveError) {
                print("iCloud save error \(saveError)")
            }
        }else{
            moc.reset()
        }
    }
    //TODO: Implement Refresh your User Interface.
}

func storeDidImportUbiquitousContent(notification: NSNotification) {
    println("Called storeDidImportUbiquitousContent")
    var moc: NSManagedObjectContext = self.managedObjectContext!
    moc.performBlock { () -> Void in
        moc.mergeChangesFromContextDidSaveNotification(notification)
    }
}

// MARK: - Core Data Saving support
func saveContext () {
    if let moc = self.managedObjectContext {
        var error: NSError? = nil
        if moc.hasChanges && !moc.save(&error) {
            // Replace this implementation 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()
        }
    }
}

获取请求的示例

class func getReceipesFormCoreData() -> [Recipes] {
    let managedContext = getManagedObjectContext()
    let request: NSFetchRequest = NSFetchRequest()

    let entity: NSEntityDescription = NSEntityDescription.entityForName("Recipes",
        inManagedObjectContext: managedContext)!

    request.entity = entity
    var error: NSError?

    var results: [Recipes] = managedContext.executeFetchRequest(request, error: &error)
        as [Recipes]
    if (error != nil) {
        println("ERROR: Could not load \(error), \(error?.userInfo)")
    }

    return results
}

2
你确定你的实体已经被彻底删除了吗?如果在应用程序终止后它们再次出现,那么似乎你的代码只是在错误地获取它们... - Lyndsey Scott
我该如何开始调试?当我启动应用程序时,获取方法返回所有实体,但当我从后台恢复它时,获取方法返回0个对象。 - Gnurant
2
我建议您发布您的代码,并准确展示它在应用程序生命周期中的运行位置。 - Lyndsey Scott
我同意,一些代码会让观点更加清晰。 - Nicola Miotto
请检查在切换到后台和返回前台时,您的managedObjectContext是否发生了变化。您的代码没有显示在切换到和从后台返回时所做的操作。 - Duncan Groenewald
1个回答

0
你是否触发了saveContext()函数? 如果没有,请尝试在AppDelegatefunc applicationDidEnterBackground(application: UIApplication)中调用它。
此外,你也可以在创建完CoreData对象后立即调用它。

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