合并CoreData托管上下文时出现异常/崩溃

时间:2012-02-10 20:43:31

标签: iphone objective-c ios core-data ios5

尝试将托管上下文(在后台线程上运行)与我的主要托管上下文(在mainthread上)合并时,我得到以下异常。我似乎无法在我自己的@try表达式中捕获异常。有没有人对此问题有任何见解?

我正在使用默认的合并策略,但我不确定这是否正确 - 这个问题非常间歇性 - 很少发生,但导致我的应用程序崩溃。

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

我在nsoperation的start()中初始化背景上下文,如下所示:

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上调用。

1 个答案:

答案 0 :(得分:0)

这个怎么样:

(所有在AppDelegate中,从后台线程调用freshContextForBackgroundTask并使用save:来触发合并。)注意syncObj是一个普通的NSObject实例,在使用许多后台线程时(或者只是运气不好)需要在app委托中进行同步调度)

-(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];

    });
}

你的方法似乎很奇怪。特别是当你将app delegate的持久存储设置为新的初始化上下文中的(nil)时。