2012-02-10 19 views
3

管理コンテキスト(バックグラウンドスレッドで実行中)とメイン管理コンテキスト(mainthread上)をマージしようとすると、次の例外が発生します。私は自分の@try式で例外をキャッチするように思えません。誰もがこの問題の洞察を持っていますか?CoreData管理コンテキストをマージするときに例外/クラッシュが発生する

デフォルトのマージポリシーを使用していますが、これが正しいかどうかわからない - この問題は非常に断続的です - まれにしか発生せず、アプリがクラッシュする原因になります。そのようなnsoperationの

Exception Type: EXC_CRASH (SIGABRT) 
Exception Codes: 0x00000000, 0x00000000 
Crashed Thread: 0 

Last Exception Backtrace: 
0 CoreFoundation     0x37e3b8bf __exceptionPreprocess + 163 
1 libobjc.A.dylib     0x319211e5 objc_exception_throw + 33 
2 CoreData      0x344b7ea5 -[NSSQLiteStatement cachedSQLiteStatement] + 1 
3 CoreData      0x344b774f -[NSSQLiteConnection prepareSQLStatement:] + 55 
4 CoreData      0x3455b049 -[NSSQLChannel selectRowsWithCachedStatement:] + 61 
5 CoreData      0x34586d63 newFetchedRowsForFetchPlan_MT + 783 
6 CoreData      0x344bfb07 -[NSSQLCore newRowsForFetchPlan:] + 351 
7 CoreData      0x34565011 -[NSSQLCore fetchRowForObjectID:] + 1005 
8 CoreData      0x344d1a57 -[NSSQLCore newValuesForObjectWithID:withContext:error:] + 195 
9 CoreData      0x344d0f83 _PFFaultHandlerLookupRow + 423 
10 CoreData      0x3450e111 -[NSFaultHandler fulfillFault:withContext:] + 25 
11 CoreData      0x34518999 -[NSManagedObject(_NSInternalMethods) _newPropertiesForRetainedTypes:andCopiedTypes:preserveFaults:] + 77 
12 CoreData      0x345178ef -[NSManagedObject(_NSInternalMethods) _newAllPropertiesWithRelationshipFaultsIntact__] + 79 
13 CoreData      0x345284db -[NSManagedObjectContext(_NSInternalChangeProcessing) _establishEventSnapshotsForObject:] + 47 
14 CoreData      0x3452694b -[NSManagedObjectContext deleteObject:] + 155 
15 CoreData      0x345238a1 -[NSManagedObjectContext _mergeChangesFromDidSaveDictionary:usingObjectIDs:] + 813 
16 CoreData      0x34522c35 -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:] + 189 
17 myapp      0x0008f0e9 0x8d000 + 8425 
18 CoreFoundation     0x37d9a22b -[NSObject performSelector:withObject:] + 43 
19 Foundation      0x31d75757 __NSThreadPerformPerform + 351 
20 CoreFoundation     0x37e0fb03 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15 
21 CoreFoundation     0x37e0f2cf __CFRunLoopDoSources0 + 215 
22 CoreFoundation     0x37e0e075 __CFRunLoopRun + 653 
23 CoreFoundation     0x37d914dd CFRunLoopRunSpecific + 301 
24 CoreFoundation     0x37d913a5 CFRunLoopRunInMode + 105 
25 GraphicsServices    0x3790ffcd GSEventRunModal + 157 
26 UIKit       0x35221743 UIApplicationMain + 1091 

私は(スタートでバックグラウンド・コンテキストを初期化):

AppDelegate *appController = [[UIApplication sharedApplication] delegate]; 
_managedObjectContext = [[NSManagedObjectContext alloc] init]; 
[appController setPersistentStore:_managedObjectContext]; 
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedDeletedObjects:) name:NSManagedObjectContextDidSaveNotification object:_managedObjectContext]; 

私はまた、オブジェクトが背景に管理コンテキストに削除されたときに呼び出される通知イベントを設定し、コールバックは次のようになります。

-(void)receivedDeletedObjects:(NSNotification *)note 
{ 
    AppDelegate *appController = [[UIApplication sharedApplication] delegate]; 
NSManagedObjectContext *mainContext = [self managedObjectContext]; 
[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:) withObject:note waitUntilDone:NO]; 

} 

これはかなりコードです。私は4つの異なるバックグラウンドスレッドを持っています。それぞれの管理されたコンテキストは、このようにメインコンテキストとマージする同じことをしています。複数のスレッドが同時にmergeChangesFromContextDidSaveNotificationに入っているのではないかと思っていますが、これは常にmainthreadで呼び出されるため、このようにはなりません。

+0

いくつかのソースコードは、特にマージを行っている場合や、追加のコンテキストを作成する場合に便利です。 – twilson

+0

こんにちはtwilson iveは上にいくつかのコードを追加しました.. – mike

+0

興味深いことに、なぜあなたは 'performSelectorOnMainThread:withObject:waitUntilDone:'をなぜ呼び出すのですか? – twilson

答えて

0

これはどう:

(すべてAppDelegateで、バックグラウンドスレッドからfreshContextForBackgroundTaskを呼び出し、保存を使用します。マージをトリガーする)syncobjでは多くを使用した場合、アプリのデリゲート内の同期のために必要な無地NSObjectのインスタンスであることに注意してくださいバックグラウンドスレッド(または単にスケジューリングで不運があります)

-(NSManagedObjectContext*) freshContextForBackgroundTask { 
    @synchronized(syncObj) { 
     NSManagedObjectContext* r = [[NSManagedObjectContext alloc] init]; 
     [r setPersistentStoreCoordinator:self.managedObjectContext.persistentStoreCoordinator]; 
     [[NSNotificationCenter defaultCenter] addObserver:self 
               selector:@selector(backgroundContextDidSave:) 
                name:NSManagedObjectContextDidSaveNotification 
                object:r]; 
     return r; 
    } 
} 


- (void)backgroundContextDidSave:(NSNotification *)notification { 
    /* Make sure we're on the main thread when updating the main context */ 
    //NSLog(@"merging change: %@",notification); 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     NSManagedObjectContext *context = [self managedObjectContext]; 
     // this for loop may not be needed for your purpose. 
     for(NSManagedObject *object in [[notification userInfo] objectForKey:NSUpdatedObjectsKey]) { 
      [[context objectWithID:[object objectID]] willAccessValueForKey:nil]; 
     } 
     [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification]; 

    }); 
} 

あなたのアプローチは変わっているようです。特に、新しく初期化されたコンテキストの1つ(nil)にアプリケーションデリゲートの永続ストアを設定したとき。

関連する問題