2015-04-12 51 views
1

我正在使用GDCoreDataConcurrencyDebugging並且我不完全理解我得到的錯誤。我使用AFNetworking來獲取一些數據,並在成功塊中將響應保存在覈心數據中。核心數據。無效的對管理對象的併發訪問調用'release'

我可以用下面的代碼錯誤:

NSURL *baseURL = ... 
AFHTTPRequestOperationManager *operationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL]; 

[operationManager GET:@"layouts" 
      parameters:nil 
       success:^(AFHTTPRequestOperation *operation, id responseObject){ 

        // backgroundManagedObjectContext is of NSPrivateQueueConcurrencyType 
        NSManagedObjectContext *context = [AppDelegate backgroundManagedObjectContext]; 

        [context performBlock:^{ 

         // Fetch and modify some NSManagedObject 
         NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Layout"];       
         Layout *layout = [context executeFetchRequest:request error:nil][0]; 

         // Remove this and the error goes away 
         layout.name = @"foo";       

         // Or this, and the error goes away 
         [context save:nil]; 

        }]; 
       } failure:^(AFHTTPRequestOperation *operation, NSError *error){}]; 

錯誤消息從GDCoreDataConcurrencyDebugging如下:

Invalid concurrent access to managed object calling 'release'; Stacktrace: (
0 Econ        0x000000010016fba3 ValidateConcurrency + 346 
1 Econ        0x000000010016f85c CustomSubclassRelease + 18 
2 CoreFoundation      0x00000001035718eb CFRelease + 603 
3 CoreFoundation      0x0000000103580a82 __CFBasicHashDrain + 322 
4 CoreFoundation      0x000000010357180c CFRelease + 380 
5 CoreFoundation      0x00000001035a2c4d -[__NSDictionaryM dealloc] + 157 
6 libobjc.A.dylib      0x0000000102ff128e _ZN11objc_object17sidetable_releaseEb + 236 
7 Foundation       0x0000000101261e0b -[NSConcreteNotification dealloc] + 84 
8 libobjc.A.dylib      0x0000000102ff128e _ZN11objc_object17sidetable_releaseEb + 236 
9 Econ        0x0000000100022e8b __destroy_helper_block_426 + 59 
10 libsystem_sim_blocks.dylib   0x000000010608a734 _Block_release + 196 
11 CoreData       0x0000000100abbb61 developerSubmittedBlockToNSManagedObjectContextPerform + 433 
12 libdispatch.dylib     0x0000000106010614 _dispatch_client_callout + 8 
13 libdispatch.dylib     0x0000000105ff8a1c _dispatch_main_queue_callback_4CF + 1664 
14 CoreFoundation      0x00000001036031f9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9 
15 CoreFoundation      0x00000001035c4dcb __CFRunLoopRun + 2043 
16 CoreFoundation      0x00000001035c4366 CFRunLoopRunSpecific + 470 
17 GraphicsServices     0x0000000105818a3e GSEventRunModal + 161 
18 UIKit        0x0000000101cd1900 UIApplicationMain + 1282 
19 Econ        0x00000001000a28ef main + 111 
20 libdyld.dylib      0x0000000106044145 start + 1 
21 ???         0x0000000000000003 0x0 + 3 
) 

我缺少什麼?

+0

看起來像您的後臺託管對象上下文可能忙於其他事情。 – Mundi

+0

它不應該,但如果是這樣,它將如何解釋錯誤信息? – andershqst

回答

0

它看起來像是錯誤是由後臺線程訪問您的託管對象Layout造成的。看起來您的Layout對象在您訪問它時已經發布。

說完看了一眼看來docsperformBlock:具有以下討論的方法:

您使用此方法如果上下文是使用NSPrivateQueueConcurrencyTypeNSMainQueueConcurrencyType初始化將消息發送到管理對象。這個方法封裝了一個autorelease池和一個對processPendingChanges的調用。

我認爲這裏的關鍵是,perfomBlock:封裝自動釋放池的事實。自動釋放池設計爲主動釋放所有對象,將其添加到併發情況中,並且可能會出現奇怪的行爲。如果你注意到你的堆棧跟蹤中有系統調用_Block_release,這可能是罪魁禍首。我並不完全確定,但我相信performBlock:方法將塊排隊,然後在上下文方便時執行它(因此異步)。系統可能會在塊有機會運行之前釋放關鍵資源。

我會嘗試使用任何performBlockAndWait:這是一個同步通話,並沒有在docs自動釋放池提。或者,使用標準NSManagedObjectContext,使用dispatch_async(dispatch_get_main_queue(), ^{})在主線程上執行代碼。或者忘記撥打performBlock:

+0

我認爲問題是我在後臺上下文中處理的NSManagedObject是從另一個線程中釋放的。因此,有關「釋放」的警告。我會認爲'performBlock:'的autorelease池會釋放後臺線程中的對象。使用'performBlockAndWait:'不是一個選項,因爲這是爲了在後臺獲取大量數據。 – andershqst

+0

首先跳入主線程如何? –

+0

成功塊在主線程上運行。修改layout.name並調用'save:'必須在'performBlock:'中完成 – andershqst

相關問題