【问题标题】:Exception / Crash When Merging CoreData Managed Contexts合并 CoreData 托管上下文时出现异常/崩溃
【发布时间】:2012-03-03 07:43:23
【问题描述】:

我在尝试将托管上下文(在后台线程上运行)与我的主托管上下文(在主线程上)合并时遇到以下异常。我似乎无法在我自己的 @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 但这不应该是这种情况,因为它总是在主线程上调用。

【问题讨论】:

  • 一些源代码会很有用,特别是在您进行合并和创建附加上下文的地方。
  • 嗨 twilson 我在上面添加了一些代码..
  • 出于兴趣,你为什么打电话给performSelectorOnMainThread:withObject:waitUntilDone:,因为真的所有这些都应该发生在主线程上?
  • _managedObjectContext你的主线程/原始上下文吗?
  • _managedObjectContext 是后台线程上下文。我调用 performSelectorOnMainThread:withObject:waitUntilDone:因为你不能在不同的线程上混合 managedobjectcontexts。所以这可以确保在主线程上调用 mainContext mergeChangesFromContextDidSaveNotification

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


【解决方案1】:

这个怎么样:

(全部在 AppDelegate 中,从后台线程调用 freshContextForBackgroundTask 并使用 save: 来触发合并。)注意 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];

    });
}

你的方法似乎很奇怪。尤其是当您将应用代理的持久存储设置为(nil)新初始化的上下文之一时。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-23
    • 2014-10-21
    • 1970-01-01
    相关资源
    最近更新 更多