RestKit 在 RKManagedObjectRequestOperation objc_msgSend 期间崩溃
Posted
技术标签:
【中文标题】RestKit 在 RKManagedObjectRequestOperation objc_msgSend 期间崩溃【英文标题】:RestKit Crashing during RKManagedObjectRequestOperation objc_msgSend 【发布时间】:2014-04-25 18:52:57 【问题描述】:我有一个函数,我们称之为“更新函数”,它向我的服务器发送一个 RKManagedObjectRequestOperation 来检索一些对象。我将此操作配置为自动 saveToPersistentStore,然后启动它。在 RKManagedObjectRequestOperation 的“成功”完成处理程序中,我调用了一个函数,该函数执行 NSFetchRequest 以获取满足特定条件的对象的更新列表,如果完成块中有新数据,则传回该数组和一个 BOOL 标志。
在“更新函数”的完成处理程序中,我调用了一个名为 getUpdatedList 的函数,它执行 NSFetchRequest 请求,如下所示:
NSUInteger now = [[NSDate date] timeIntervalSince1970];
NSArray *predicates = @[
[NSPredicate predicateWithFormat:@"endAt > %d", now],
[NSPredicate predicateWithFormat:@"deleted != %@", @YES]
];
NSManagedObjectContext *managedObjectContext = [self managedObjectContext]; //(REMOVED: _objectManager.managedObjectStore.persistentStoreManagedObjectContext;)
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
[fetchRequest setPredicate:compoundPredicate];
NSError *error = nil;
NSArray *fetchedRecords = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (sortDescriptor)
fetchedRecords = [fetchedRecords sortedArrayUsingDescriptors:@[sortDescriptor]];
DDLogInfo(@"Retrieving list of %@ objects from local database - got %d results.", entityName, fetchedRecords.count);
return fetchedRecords;
- (NSManagedObjectContext *)managedObjectContext
if (_globalContext != nil)
return _globalContext;
NSPersistentStoreCoordinator *coordinator = _objectManager.managedObjectStore.persistentStoreCoordinator;
if (coordinator != nil)
_globalContext = [[NSManagedObjectContext alloc] init];
[_globalContext setPersistentStoreCoordinator:coordinator];
return _globalContext;
现在,我自己从未亲眼目睹过这种崩溃,所以我不知道到底发生了什么,但在我的日志中,我发现它说“从本地数据库中检索 %@ 对象的列表 - 得到了x 结果。”,然后日志记录将重新开始,这在应用程序崩溃时发生。在这个 RKManagedObjectRequestOperation 中的某个地方并返回更新的列表,应用程序崩溃了 1/1000 次......
以下是我从 Crashlytics 获得的堆栈跟踪之一。有许多函数调用“更新函数”,一些来自后台,一些在前台,但所有堆栈跟踪都引用了这个“更新函数”,您可以在下面的第 9 行看到它(updateAndFetchInfoWithCompletionHandler):
Thread : com.apple.uikit.backgroundTaskAssertionQueue
0 libsystem_kernel.dylib 0x38911a50 mach_msg_trap + 20
1 libsystem_kernel.dylib 0x3891184d mach_msg + 40
2 SpringBoardServices 0x34d2b42d SBGetBackgroundTimeRemaining + 52
3 SpringBoardServices 0x34d29461 SBSGetBackgroundTimeRemaining + 36
4 UIKit 0x30685b23 __40-[UIApplication backgroundTimeRemaining]_block_invoke + 10
5 libdispatch.dylib 0x38858d3f _dispatch_client_callout + 22
6 libdispatch.dylib 0x3885d6c3 _dispatch_barrier_sync_f_invoke + 26
7 UIKit 0x30685a97 -[UIApplication backgroundTimeRemaining] + 182
8 <redacted> 0x002345df __46-[LocationManager handleExitedRegion]_block_invoke_2 (LocationManager.m:262)
9 <redacted> 0x002451e3 __57-[DataManager updateAndFetchInfoWithCompletionHandler:]_block_invoke (DataManager.m:719)
10 <redacted> 0x00340d0d __66-[RKObjectRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke229 (RKObjectRequestOperation.m:506)
11 libdispatch.dylib 0x38858d53 _dispatch_call_block_and_release + 10
12 libdispatch.dylib 0x38858d3f _dispatch_client_callout + 22
13 libdispatch.dylib 0x3885b6c3 _dispatch_main_queue_callback_4CF + 278
14 CoreFoundation 0x2dba3681 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8
15 CoreFoundation 0x2dba1f4d __CFRunLoopRun + 1308
16 CoreFoundation 0x2db0c769 CFRunLoopRunSpecific + 524
17 CoreFoundation 0x2db0c54b CFRunLoopRunInMode + 106
18 GraphicsServices 0x32a796d3 GSEventRunModal + 138
19 UIKit 0x3046b891 UIApplicationMain + 1136
20 <redacted> 0x000a3197 main (main.m:18)
这里有什么明显的我遗漏的东西导致了所有这些崩溃吗?
编辑:更改上述代码以反映 cmets 之后的不同托管对象上下文。
【问题讨论】:
【参考方案1】:您不应该使用persistentStoreManagedObjectContext
。如果此代码在主线程上运行,那么您必须使用主队列上下文。如果在任意后台线程上运行,则必须专门为该调用创建一个新上下文。
上下文是特定于线程的,您必须尊重您创建的每个上下文的线程所有权。
在后台线程上运行时,使用newChildManagedObjectContextWithConcurrencyType:tracksChanges:
创建一个新上下文。这维护了上下文所需的线程限制。
【讨论】:
非常有趣。在 RKManagedObjectRequestOperation 的成功/失败块内运行的代码是否在主线程上运行?如果是这样,是的,这是在主线程上运行的。你说的是我需要改变我正在使用的 managedObjectContext 吗?我肯定不是核心数据专家。感谢您迄今为止的帮助。 其实我认为直接运行操作并不会切换线程。但是你绝对不应该使用持久化上下文。或者,如果您这样做,您必须在执行块中执行 fetch。 我只需要从我的应用程序的核心数据中检索 2 组对象。我应该如何创建和管理上下文?我可以有一个用于两者,还是每次我去获取对象时都需要创建一个? 好的,抱歉,再添加一个。我相信通过添加上述更改,我已经让它工作了。让我知道我的编辑是否更“正确”。 更新了答案,推荐了创建上下文的方法(特定于线程,而不是全局)。如果你能保证单线程使用,那么“全局”就可以了。以上是关于RestKit 在 RKManagedObjectRequestOperation objc_msgSend 期间崩溃的主要内容,如果未能解决你的问题,请参考以下文章
在 xcodebuild 期间未找到 RestKit/RestKit.h' 文件错误
xCode 4.3 使用 RestKit 归档项目失败:#import <RestKit/RestKit.h> Not found