2013-08-28 72 views
0
-(void)someBackgroundTask { 
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]; 
    [context setPersistentStoreCoordinator:[self coordinator]]; 

    // ... 

    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 
    [notificationCenter addObserver:self selector:@selector(handleSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:context]; 

    [context save:&error]; 

    // safe? 
    [notificationCenter removeObserver:self name:NSManagedObjectContextDidSaveNotification object:context]; 

    // ... 
} 


// meanwhile on the main thread... 
-(void)handleSaveNotification:(NSNotification *)notification { 
    [[self context] mergeChangesFromContextDidSaveNotification:notification]; 
} 

在致電​​之後很快就可以移除觀察者嗎?CoreData:在save:call後立即刪除'didSave'通知。太快了?

回答

1

只要你收到你想要的通知,它不會太早。但是該代碼還存在其他問題。

添加觀察者,觸發通知,然後刪除觀察者沒有任何意義。您也可以直接撥打handleSaveNotification方法,而不是打擾通知。這將有相同的效果,減少工作。

原因是通知是在他們發佈在上的帖子上同步發佈的。因此,如果someBackgroundTask實際上在後臺線程或隊列上運行,handleSaveNotification也將在後臺運行。使用這樣的通知不會讓你跨線程。要在主線程上執行合併,您有幾個選項,其中包括:

  • 使用addObserverForName:object:queue:usingBlock:註冊通知。使用該方法,您可以告知通知中心要使用哪個隊列。確保保存對此方法返回的對象的引用 - 稍後您將需要刪除該觀察者。
  • 直接調用合併方法,但在該方法中使用dispatch_asyncperformSelectorOnMainThread:withObject:waitUntilDone:將合併移到主線程。
+0

謝謝,湯姆。我通過在每個點上記錄'[thread description]'來檢查,你是對的(當然)。所以我使用你的後者。我已經向蘋果公司提出了一項改進他們的CoreData文檔的建議,至少在這一點上還不清楚。現在到我的問題的其餘部分:我是不是在主線程和這個後臺線程之間建立一個競賽? – QED

+1

「save:」通知將在'save:'回調之前發佈,因此您可以立即刪除觀察者。如果不使用通知,直接調用合併方法仍然會更簡單和更清晰。 –