阅读背景:

核心数据iCloud直到第二次启动才会填充tableview

来源:互联网 

I have created an app that utilizes Core Data with iCloud. It seems that I have all the difficult pieces working correctly but am missing something really important. Once installed on two physical devices, changes on one appear as expected on the second. The issue is that I must install the app, then close it and relaunch it before ANY data appears in the main tableview. Xcode 6.3.1 iOS 8.3

我创建了一个利用iCloud核心数据的应用程序。似乎我所有的困难部分都正常工作,但我错过了一些非常重要的东西。一旦安装在两个物理设备上,一个上的更改在第二个上显示为预期。问题是我必须安装应用程序,然后关闭它并在主数据视图中出现任何数据之前重新启动它。 Xcode 6.3.1 iOS 8.3

This is true for each device. When the app has been deleted from both devices, I install the app on one device. I receive this on the console:

每个设备都是如此。从两台设备上删除应用程序后,我会在一台设备上安装该应用程序。我在控制台上收到了这个:

2015-05-04 15:33:05.297 BiopLogCloud[1353:734999] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: mobile~C1432E0B-D885-418C-996C-5E6CDD45D7F1:BiopLogCloudStore Using local storage: 1 The count is 0 inside persistentStoreDidChange inside persistentStoreDidChange inside persistentStoreDidChange inside persistentStoreDidChange inside persistentStoreDidChange inside persistentStoreDidChange inside persistentStoreDidChange inside persistentStoreWillChange inside persistentStoreDidChange 2015-05-04 15:33:06.979 BiopLogCloud[1353:735018] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: mobile~C1432E0B-D885-418C-996C-5E6CDD45D7F1:BiopLogCloudStore Using local storage: 0

2015-05-04 15:33:05.297 BiopLogCloud [1353:734999] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage :: CoreData:Ubiquity:mobile~C1432E0B-D885-418C-996C-5E6CDD45D7F1:BiopLogCloudStore使用本地存储:1内部的persistentStoreDidChange中的计数为0 persistentStoreDidChange内部persistentStoreDidChange内部persistentStoreDidChange内部persistentStoreDidChange内部persistentStoreDidChange内部persistentStoreDidChange内部persistentStoreWillChange内部persistentStoreDidChange 2015年5月4日15:33:06.979 BiopLogCloud [1353:735018] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage :: CoreData:普遍性:移动〜C1432E0B-D885-418C-996C- 5E6CDD45D7F1:BiopLogCloudStore使用本地存储:0

Note the count variable - at zero. Then I relaunch the app and the data is present. It does not matter whether I Build and Run from Xcode or simply launch the app from the device. The data appears instantly and if launched from Xcode I receive the following in the console:

注意count变量 - 为零。然后我重新启动应用程序,数据存在。无论我是从Xcode构建还是运行,还是只是从设备启动应用程序。数据立即出现,如果从Xcode启动,我在控制台中收到以下内容:

2015-05-04 15:35:03.542 BiopLogCloud[1358:735588] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: mobile~C1432E0B-D885-418C-996C-5E6CDD45D7F1:BiopLogCloudStore Using local storage: 1 The count is 12 inside persistentStoreDidChange 2015-05-04 15:35:04.062 BiopLogCloud[1358:735625] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: mobile~C1432E0B-D885-418C-996C-5E6CDD45D7F1:BiopLogCloudStore Using local storage: 0

2015-05-04 15:35:03.542 BiopLogCloud [1358:735588] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage :: CoreData:Ubiquity:mobile~C1432E0B-D885-418C-996C-5E6CDD45D7F1:BiopLogCloudStore使用本地存储:1在persistentStoreDidChange 2015中计数为12 -05-04 15:35:04.062 BiopLogCloud [1358:735625] -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage :: CoreData:Ubiquity:mobile~C1432E0B-D885-418C-996C-5E6CDD45D7F1:BiopLogCloudStore使用本地存储:0

After repeating the same process on the second device the app works as expected.

在第二个设备上重复相同的过程后,应用程序按预期工作。

Since it works after this initial issue, I'm not sure what code to show, but here is the relevant persistent store and fetched results code:

由于它在这个初始问题之后工作,我不确定要显示的代码,但这里是相关的持久存储和获取结果代码:

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {

    var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)

    let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask).last as! NSURL

    let storeURL = documentsDirectory.URLByAppendingPathComponent("BiopLogCloud.sqlite")

    //if the store is incompatible
    //NSFileManager.defaultManager().removeItemAtURL(url, error: nil)
    //nuke it

    var error: NSError? = nil
    var failureReason = "There was an error creating or loading the application's saved data."

    let storeOptions = [NSPersistentStoreUbiquitousContentNameKey : "BiopLogCloudStore"]

    if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: storeOptions, error: &error) == nil {
        coordinator = nil
        // Report any error we got.
        let dict = NSMutableDictionary()
        dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data - cloud persistent store not created"
        dict[NSLocalizedFailureReasonErrorKey] = failureReason
        dict[NSUnderlyingErrorKey] = error
        error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict as [NSObject : AnyObject])
        // Remember to create an alert for the user in case of error
        NSLog("Unresolved error \(error), \(error!.userInfo)")
        abort()
    }

    return coordinator
}()

lazy var managedObjectContext: NSManagedObjectContext? = {

    let coordinator = self.persistentStoreCoordinator
    if coordinator == nil {
        println("YES! You have found the issue - coordinator is nil")
        return nil 
    }

    var managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = coordinator

    return managedObjectContext
}()

var fetchedResultsController: NSFetchedResultsController {

    if myFetchedResultsController != nil {
        return myFetchedResultsController!
    }

    let fetchRequest = NSFetchRequest()

    // Edit the entity name as appropriate auto generate didn't work - fix that
    let entity = NSEntityDescription.entityForName("Patient", inManagedObjectContext: managedObjectContext)

    fetchRequest.entity = entity

    // Set the batch size to a suitable number.
    fetchRequest.fetchBatchSize = 50

    // Edit the sort keys as appropriate.
    let sortDescriptor = NSSortDescriptor(key: "dateEntered", ascending: false)
    let sortDescriptors = [sortDescriptor]

    fetchRequest.sortDescriptors = [sortDescriptor]

    let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: "PatientCache")

    var countError : NSError? = nil
    var count = managedObjectContext.countForFetchRequest(fetchRequest, error: &countError)
    println("The count is \(count)")

    aFetchedResultsController.delegate = self
    myFetchedResultsController = aFetchedResultsController

    var error: NSError? = nil
    if !myFetchedResultsController!.performFetch(&error) {
         // Replace this implementation with code to handle the error appropriately.

         println("Unresolved error \(error), \(error!.userInfo)")
         abort()
    }

    return myFetchedResultsController!
}    
var myFetchedResultsController: NSFetchedResultsController? = nil

2 个解决方案

#1


One scenario is that you're either not listening for NSPersistentStoreDidImportUbiquitousContentChangesNotification or not updating your table view when it arrives. That notification is how you know that new data has arrived from iCloud. If you don't handle it correctly, your app won't display any new data until you force it to reload its data-- such as by killing the app and re-launching it.

一种情况是您要么没有监听NSPersistentStoreDidImportUbiquitousContentChangesNotification,要么在它到达时不更新表视图。该通知是您如何知道新数据来自iCloud的。如果您没有正确处理它,您的应用程序将不会显示任何新数据,直到您强制它重新加载其数据 - 例如通过终止应用程序并重新启动它。

#2


I too struggled with this issue for an embarrassingly long time. It seems as though somewhere in the local creation process the table view controller thinks it has a good connection to the data when it really does not.

我在这个问题上挣扎了很长时间。似乎在本地创建过程中的某个地方,表视图控制器认为它与数据有良好的连接,而实际上并没有。

If you are using the standard xcode app for a tableview, fetched results controller and icloud I found that all I needed to do was place some code in the function called by the notification center when the stores change.

如果您使用标准xcode应用程序进行tableview,取得结果控制器和icloud我发现我需要做的就是在商店更改时在通知中心调用的函数中放置一些代码。

xcode sets a helper fetchedResultsController

xcode设置了一个helper fetchedResultsController

var _fetchedResultsController: NSFetchedResultsController? = nil

If you set it to nil, then call for recreation of the fetchedResultsController you should be good to go. Again, the standard variable frc with modifications is what I use:

如果你把它设置为nil,然后调用fetchedResultsController的重新创建你应该很高兴去。同样,我使用的是带有修改的标准变量frc:

var fetchedResultsController: NSFetchedResultsController {
    if _fetchedResultsController != nil {
        return _fetchedResultsController!
    }

    ...bunch more code
}

So in the function I named handleStoresDidChange(..), nil the frc and recreate it

所以在我命名为handleStoresDidChange(..)的函数中,没有frc并重新创建它

func handleStoresDidChange(notification : NSNotification) {

    print("storesDidChange notification:\(notification)")
    self.view.userInteractionEnabled = true

    _fetchedResultsController = nil
    self.fetchedResultsController
    tableView.reloadData()

}//handleStoresDidChange

Hope that works for you.

希望对你有用。


分享到: