2014-01-07 15 views
2

我在主線程中創建實體藝術家, 然後在後臺線程中傳遞它並與實體相關聯。通過MagicalRecords在不同線程中使用NSManagedObject

如何正確地做到這一點?

- (IBAction)add:(id)sender 
{ 
    Artist *artist = [Artist MR_createEntity]; 
    artist.title = @"Eminem"; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{ 
     // here a large calculation 
     Album *album = [Album MR_createEntity]; 
     album.title = @"Album 1"; 
     [artist setAlbums:[NSSet setWithArray:@[album]]]; 

     dispatch_async(dispatch_get_main_queue(),^{ 
      [artist.managedObjectContext MR_saveToPersistentStoreAndWait]; 
     }); 
    }); 
} 

錯誤:

MagicalRecordTest[2008:1803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'albums' between objects in different contexts (source = <Artist: 0x15eaa2d0> 
+0

你應該真的在使用來自魔法記錄的特定線程調用。我認爲它是'performBlock'。 – Fogmeister

回答

5

你違反了核心數據的基本規則之一。 A NSManagedObjectContext及其關聯的NSManagedObject實例只能在創建它們的線程上訪問。您可以通過NSManagedObjectID實例但不包含NSManagedObject實例。

此外,當您創建兩個NSManagedObject實例之間的關係時;兩個實例必須來自相同的NSManagedObjectContext否則你會得到你在上面看到的錯誤。

取代上述方法,重新獲取塊中的Artist。我可以提供有關如何使用Core Data執行此操作的示例代碼,但您需要研究如何使用MagicalRecord執行此操作。

+0

+1在MagicalRecord中重新讀取,你可以做'[artist inThreadContext]'我相信。反正就是這樣。 – Fogmeister

+1

MR_inThreadContext方法已被棄用,因爲它與GCD隊列一起使用時偶爾會跨線程邊界。剛剛創建一個新的上下文,他們是輕量級的,正是出於這個原因。 – casademora

3

Marcus是正確的,你需要知道你正在使用的上下文,並且只需要在單個隊列或線程中使用它們。 MagicalRecord有一個很好的API來管理這個。在你的情況,你應該做更多的東西,如:

- (void) add; 
{ 
    NSManagedObjectContext *mainContext = [NSManagedObjectContext MR_defaultContext]; 
    Artist *artist = [Artist MR_createInContext:mainContext]; 
    [mainContext MR_saveToPersistentStoreAndWait]; 

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) { 
     Artist *localArtist = [artist MR_inContext:localContext]; 
     localArtist.title = @"Album..."; 
    }]; 
} 

MagicalRecord將設置保存隊列,並在適當的地方進行的事情,只要你記得第一次,你不能NSManagedOjbectContexts之間傳輸的臨時對象。其次,您必須爲每個線程/隊列/塊使用單獨的上下文。本例中的localContext是爲你創建的,一旦塊完成,MagicalRecord將嘗試爲你保存該本地/臨時上下文。

相關問題