0

我正在使用核心數據的多線程應用程序。具有諷刺意味的是,當我得知Core Data不是線程安全的時候,我認爲應用程序已經接近完成了......因此,我現在添加了多上下文,而不是從Xcode模板獲得的單一上下文到目前爲止,工作到目前爲止,真的,但這是比我猜想的技巧運氣更好)合併到父/主上下文後,子上下文對象變爲空

我試圖使用>的iOS 5.0的方法與父/子上下文,這將適合我想要做什麼,但當我在子上下文中插入有效數據/屬性的有效對象時,它們在父上下文中全部變爲零或0(取決於屬性類型)。

我注意到,有類似的帖子,但沒有任何答案;

Parent MOC get changes with empty data from child MOC

NSManagedObject values are correct, then incorrect when merging changes from parent to child NSManagedObjectContext

下面是一些代碼來獲取的想法;

我有一個單獨的管理器,用戶界面用來「做東西」,然後在任務完成時使用委託或回調。反過來這位經理有一個模型,經理來處理持久性數據管理,以及其他一些通訊經理交談的網絡/ REST的API等

- (void) doSomeStuff:(NSString*)someParam 
     callbackObject:(NSObject*)object 
      onSuccess:(SEL)successSelector 
      onFailure:(SEL)failureSelector 
{ 
    //Kick as an async thread since we don't want to disturb the UI 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), ^(void) 
    { 
     //Ask model manager for a nice context to work with... 
     //NOTE; All contexts (private ones) are stored in a NSDictionary using currentThread as key, so that we always can access the "correct" context at anytime if we need to insert/delete/change anything in the context 
     NSManagedObjectContext* privateContext = [self.modelManager getManagedObjectContext]; 

     //Perform stuff in block since our context is of NSPrivateQueueConcurrencyType 
     [privateContext performBlockAndWait:^{ 

      //... do the actual stuff, go online, talk to a REST-API, wait for things, which will eventually result in a new object being created 
      User* user = ...; 

      //Store object in model manger which is my abstraction of CoreData 
      //NOTE: the modelManager will get a reference to the currently used privateContext and use it to insert the object 
      [self.modelManager addUser:user]; 

      //Save model! 
      [self.modelManager save]; 
     }]; 

     //Trigger callback, if applicable 
     if (loggedInUserGuid && successSelector) 
     { 
      [object performSelectorOnMainThread:successSelector withObject:loggedInUserGuid waitUntilDone:NO]; 
     } 
    }); 
} 

中的ModelManager保存功能考慮到上下文併發性類型,並且在使用子/父上下文時將按照規範行事;

- (void) save 
{ 
    //Get current context... 
    NSManagedObjectContext* currentContext = [self getManagedObjectContext]; 

    //If the current context has any changes... 
    if ([currentContext hasChanges]) 
    { 
     //Changes detected! What kind of context is this? 
     switch (currentContext.concurrencyType) 
     { 
      case NSPrivateQueueConcurrencyType: 
      { 
       NSError* error = nil; 
       if (![currentContext save:&error]) 
        abort(); 

       if (self.mainManagedObjectContext hasChanges]) 
       { 
        [self.mainManagedObjectContext performBlockAndWait:^{ 

         NSError *mainError; 
         if (![self.mainManagedObjectContext save:&mainError]) 
          abort(); 

        }]; 
       } 

       break; 
      } 

      .... 

     } 
    } 
} 

通過之前和搶救孩子的情況和家長/主上下文之後加入調試輸出,我注意到,插入的對象是有很好的孩子而言,和孩子方面說「hasChanges == YES 「,而正如預期的那樣,主要上下文表示」hasChanges == NO「。

(entity: User; id: 0x10c06c8c0 <x-coredata:///User/tDFBBE194-44F9-44EC-B960-3E8E5374463318> ; data: { 
    created = nil; 
    emailAddress = "[email protected]"; 
    firstName = Wilton; 
    guid = "2eaa77fa-0d2c-41b8-b965-c4dced6eb54a"; 
    lastName = Millfjord; 
    nbrOfOfflineKeys = 5; 
    password = 123456; 
}) 

主上下文後保存爲好,並期待它在保存前的registeredObjects,我們可以看到,「hasChanges == YES」(預期後,孩子的節約插入的對象/合併到它的父但是,另外 - 所有PARAMS和屬性現在爲零或0取決於屬性類型...;

(entity: User; id: 0x10c06c8c0 <x-coredata:///User/tDFBBE194-44F9-44EC-B960-3E8E5374463318> ; data: { 
    created = nil; 
    emailAddress = nil; 
    firstName = nil; 
    guid = nil; 
    lastName = nil; 
    nbrOfOfflineKeys = 0; 
    password = nil; 
}) 

正如你所看到的,ID是一樣的,所以它的「相同」的對象,但沒有/重置內容我已經嘗試了所有「setMergePolicy」的各種組合,但沒有效果。我甚至嘗試過使用iOS 5.0方法添加一個NSNotificationCentre方法,其中我「mergeChangesFromContextDidSaveNotification」,並且唯一可以驗證的是NSNotification參數中的數據是有效的,並且是「好數據」,但主要上下文仍未正確更新。結果仍然是一個空洞的對象。

期待您的想法和想法。

/馬庫斯

更新

創建新的管理對象時,使用的主要方面,無論所使用的代碼線程/被當時正在執行上下文performBlock ...

NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:self.mainManagedObjectContext]; 
User* user = (User *)[[User alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; 

對象用戶其後懸掛沒有上下文,直到後來,當我決定將其添加到管理範圍內(使用我的getManagedObjectContext到GE適當/當前上下文)。

[[self getManagedObjectContext] insertObject:user]; 
+0

您是否嘗試過使用performBlock:而不是performBlockAndWait?看着你的問題和你鏈接的其他兩個人,我唯一注意到的是你全部使用了performBlockAndWait。你有什麼理由想等待?我使用CoreData時遵循類似的模式,但我只使用performBlock。 – TheJer

+0

我試圖改變執行塊,但沒有改變行爲。爲什麼我寧願performBlockAndWait是因爲我希望經理「doSomeStuff」做一些異步操作以避免干擾主線程。因此,我開始分派一個新的異步線程。一旦執行,該線程又會向modelManager請求私有上下文。因此,我認爲這足夠了異步進程,並且我們已經從主線程和UI干涉中分派出來,所以讓我們等待該塊結束。 –

+0

不過,我想知道,如果我基本上在這裏嵌套主線程的事實可能會干擾?我的意思是,主線程調用doSomeStuff調度一個異步工作線程,該線程又調用performBlockAndWait ...?一個太多了?這種方法與ref-examples有所不同,因爲我根據正在運行的線程獲取/創建私有上下文......我已經明確地看到的大多數示例都創建了一個新的私有上下文,然後執行異步(從主線程執行)? 。只是在大聲思考......我也把「保存」機制作爲一個函數,而不是內嵌在塊內的代碼......? –

回答

0

有嘗試一切,慢慢地減少我現有的代碼什麼都沒有,只是一個直行版本沒有的功能,也沒有經理後 - 只是要找準當我可以看到,在mainContext的registeredObjects是,在保存後孩子的情況下,實際上不是一個空的元素......我終於找到了答案。

事實證明,我正在創建(有意)在創建時不被管理(放在上下文中)的對象。我的想法是,當我使用REST-API /後端時,我可以將JSON響應轉換爲對象(然後懸停,無需上下文),然後與我已經存儲在模型管理器中的內容進行比較,以便我可以檢測到變化並通知用戶這些變化...

因此,我做了;

//Create object "hanging" so that we can add it to context alter on... 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:mainContext]; 
User* user = (User *)[[User alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; 

...然後,當我決定這是新東西,我想保留的東西;

//Insert it 
[privateContext insertObject:user]; 

但是,插入的對象保存在子上下文中時,會自動合併到父代的主上下文 - 清空!但是當我試圖直接將對象添加到私有上下文中時,對象在合併期間突然不會被清空;

//Create object AND insert into context now... 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:mainContext]; 
User* user = (User *)[[User alloc] initWithEntity:entity insertIntoManagedObjectContext:privateContext]; 

我不明白爲什麼,真的,但它是那裏。合併對象從小孩的私有上下文合併到父項的主要上下文時爲什麼變空的原因。我寧願不是這樣,因爲這意味着我正在運行的「更改檢測/通知」代碼的大型重構,但至少我在線程安全的CoreData;)

+0

快速反思;我會說這是CoreData中的一個錯誤? Apple在他們的文檔中說自己創建NSManagedObjects而不插入上下文是完全可行的 - 並且可以在後面的階段使用上下文的insertObject函數添加對象...但是,我在這篇文章中的發現表明,這樣的方法不能與多上下文應用程序合併,直到父/主上下文將子上下文合併,因爲對象將被清空而不再合併。有沒有人有類似的結果?這可能是一個iOS錯誤,還是「只是我」? ;) –

+0

你有沒有找到解決這個問題的方法?我只是在與完全相同的事情而戰鬥。如果要維護兩套數據模型(一種用於json存儲,一種用於coredata) - 這僅僅是爲了核心數據起作用:(但是,這正是我所做的也是這樣的,這真是太愚蠢了。一個痛苦,做一件很簡單的事情 –

+0

老實說,現在已經有一段時間了,但是我認爲當我停止使用移植和合並設置時,我的問題變得不那麼重要了,我開發的應用程序仍然很好用,並且已經重新發布iOS 8,9和10,而且在那段時間內我們還沒有任何CoreData的問題。 –

相關問題