5

我有圖像在coredata,我試圖加載懶惰的表視圖。每個單元使用相關核心數據實體的觀察者在圖像變得可用時更新圖像。在實體相關的代碼如下:使用dispatch_async與核心數據時使用dispatch_async

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    // The heavy lifting seems to be during firing of the fault and accessing data, 
    // so i'm trying to do that in the background thread. 
    UIImage *i = [UIImage imageWithData:self.imageEntity.data]; 
    // I now need to notify observers that the image is ready on the main thread 
    dispatch_async(dispatch_get_main_queue(), ^{ 
    [self willChangeValueForKey:@"image"]; 
    image = i; 
    [self didChangeValueForKey:@"image"]; 
    }); 
}); 

該項目採用ARC,我沒有得到任何編譯器錯誤或警告,當我運行它那種工作,直到我滾動快,然後我得到當我宣佈i時,線上有一個EXC_BAD_ACCESS。

缺少什麼我在這裏?

+0

你用'NSZombieEnabled'試過了嗎? – zoul 2012-02-23 06:20:40

+0

如果您不使用dispatch_async,會發生什麼情況?只是在主線上運行 – 2012-02-23 06:31:17

+0

NSZombie對我來說沒有任何額外的光線。如果我不dispatch_async它會阻止主線程和滾動真的很差。 – dizy 2012-02-23 06:35:51

回答

7

顯然提取CoreData objects is not thread safe。所以建議使用相同的persistentStoreCoordinator,但使用不同的ObjectContexts。這裏是我更新的代碼,似乎不再崩潰:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    @autoreleasepool { 
    // Create a new context 
    NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] init]; 
    // Use an existing coordinator 
    NSPersistentStoreCoordinator *coordinator = [[DataSource sharedDataSource] persistentStoreCoordinator]; 
    [backgroundContext setPersistentStoreCoordinator:coordinator]; 
    // Getting objectID does not fire the fault, so we grab it but actually fetch the object 
    // on a background context to be thread safe. 
    Image *imageEntity = (Image*)[backgroundContext objectWithID:self.imageEntity.objectID]; 
    image = [UIImage imageWithData:imageEntity.data]; 
    // Notify observers that the image is ready on the main thread 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self willChangeValueForKey:@"image"]; 
     [self didChangeValueForKey:@"image"]; 
    }); 
    } 
}); 
+0

然後,您可以將圖像保存在主線程中,位於應用程序管理的對象上下文中嗎?你會怎麼做,因爲它是在後臺線程上創建的? – SAHM 2013-11-25 01:20:20

1

迪濟,也請記住,這是在代碼中創建Image對象:

UIImage *i = [UIImage imageWithData:self.imageEntity.data]; 

設置爲自動釋放。 dispatch_async方法在主隊列上運行,因此在主線程運行調度塊時,可能會釋放爲圖像分配的內存。

+0

好點,我只是在@autoreleasepool {}中包裝整個事情來解決這個問題嗎? – dizy 2012-02-24 05:34:34

+0

我會保留在外部塊中的圖像,然後釋放它在內部塊。 – 2012-02-24 14:13:47

+0

我在項目中使用ARC – dizy 2012-02-25 03:09:59

0

CoreData不是線程安全的,您必須管理上下文以避免崩潰。 如果您計劃大量使用併發進程來更新核心數據中的數據,我建議您看一下MagicalRecord,這是一個由Active Record of Rails啓發的驚人模式,它以一種非常智能的方式處理所有這些方面。

+0

感謝您指出MagicalRecord,聽起來很棒。 – dizy 2012-02-24 05:53:02