2011-08-02 36 views
3

我遇到NSFetchedResultsController问题开发客人管理应用程序。NSFetchedResultsController委托和后台驱动更新

该应用程序基本上下载后台列表(使用NSOperation子类),将它们插入托管对象上下文,然后在UI线程的表视图中显示它们。我认为我遵循核心数据多线程规则(我有单独的MOC为其线程上创建的操作,我同步我的主MOC使用保存通知等)。

我不完全理解的是NSFetchedResultsController的行为,似乎是在后台线程而不是主线程调用其委托方法(controllerDidChangeContent等),导致非法的UI更新。

所以我的问题是 - 使用NSFetchedResultsControllerDelegate观察来自MOC的更改是否保存了通知或NSFetchedResultsControllerDelegate设计为仅与主线程上完成的更改一起工作是否合法?

我不确定我的解释是否足够清楚,如果不是,我可以张贴一些代码来演示问题。

回答

2

我的猜测是您的MOC保存通知正在发送,并在后台线程上观察到而不是主事件线程。这将导致NSFetchedResultsControllerDelegate在后台线程上发送委托消息。

你需要确保你没有保存通知观察者将控制权交给主线程,e.g:

- (void)backgroundMOCDidSaveNotifiaction:(NSNotification *)notification 
{ 
    [uiMOC performSelectorOnMainThread: 
     @selector(mergeChangesFromContextDidSaveNotification:) 
    withObject:notification waitUntilDone:NO]; 
} 
+0

感谢您的回答,我结束了您的解决方案。令我困惑的是,关于Apple文档,从后台线程调用mergeChangesFromContextDidSaveNotification(该方法设计为线程安全)是合法的。所以我想,Core Data本身会以某种方式神奇地管理在正确线程上传递给我的NSFetchedResultsController的更改。 – Martin

+0

我同意在这一点上文档混淆。它说你可以传递一个在另一个线程上发布的通知,但它并没有说它是线程安全的,或者你可以从另一个线程调用这个方法,所以这在技术上并不正确。我建议在文档页面上提交注释:http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/NSManagedObjectContext.html –

0

免责声明

Daniel Dickison响应正确的答案。我只是在这里提供一些额外的细节和解释,因为其中一些步骤并非微不足道。

使用2个不同的管理对象上下文是做

UI线程MOC正确的事情:

lazy var mainQueuemanagedObjectContext: NSManagedObjectContext = { 
    let coordinator = self.persistentStoreCoordinator 
    var managedObjectContext = NSManagedObjectContext(
     concurrencyType: .MainQueueConcurrencyType) 
    managedObjectContext.persistentStoreCoordinator = coordinator 
    return managedObjectContext 
    }() 

传输,下载,背景商务部:

lazy var transportManagedObjectContext:NSManagedObjectContext = { 
    let coordinator = CoreDataStack.sharedInstance.persistentStoreCoordinator 
    let managedObjectContext = NSManagedObjectContext(
     concurrencyType: .PrivateQueueConcurrencyType) 
    managedObjectContext.persistentStoreCoordinator = coordinator 
    return managedObjectContext 

    }() 

使用后台MOC进行后台操作:

(如新的数据被下载和保存)

transportManagedObjectContext.performBlockAndWait({() -> Void in 
    // ...add, change, delete objects, then save 
    try transportManagedObjectContext.save() 
}) 

适用于背景管理对象上下文Daniel Dickison'响应,按照所述Apple documentation

// Broadcast NSManagedObjectContextDidSaveNotification 
NSNotificationCenter.defaultCenter().addObserver(
    self, 
    selector: "mocDidSaveNotification:", 
    name: NSManagedObjectContextDidSaveNotification, 
    object: self.transportManagedObjectContext) 

func mocDidSaveNotification(notification:NSNotification) 
{ 
    mainQueuemanagedObjectContext.performSelectorOnMainThread(
     "mergeChangesFromContextDidSaveNotification:", 
     withObject: notification, 
     waitUntilDone: true) 
} 

注:我通常更喜欢使用performBlockAndWait()waitUntilDone: true,除非我肯定知道不等待不会造成竞赛状况。如果您决定不是等待,我邀请您彻底测试您的应用程序。我冒昧地让后台线程等待UI,但是反过来永远不会

从UI线程

NSFetchedResultsController必须使用MainQueueConcurrencyType管理对象上下文听。

let fetchedResultsController = NSFetchedResultsController(
    fetchRequest: fetchRequest, 
    managedObjectContext: mainQueuemanagedObjectContext, 
    sectionNameKeyPath: "yourKey", 
    cacheName: nil) 

NSFetchedResultsController从后台管理对象上下文中解脱出来,并会收到controllerWillChangeContentdidChangeObject后的合并已经完成。

相关问题