使用 RestKit 导致核心数据崩溃的多个 RKResponseDescriptor
Posted
技术标签:
【中文标题】使用 RestKit 导致核心数据崩溃的多个 RKResponseDescriptor【英文标题】:Multiple RKResponseDescriptors causing crash with Core Data with RestKit 【发布时间】:2013-04-22 00:16:47 【问题描述】:我在单例中为每个服务调用创建我的 RestKit 映射,例如:
- (void)setupMapping
RKObjectManager *objectManager = [RKObjectManager sharedManager];
RKEntityMapping *challengesMapping = [RKEntityMapping mappingForEntityForName:@"Challenge" inManagedObjectStore:[objectManager managedObjectStore]];
[challengesMapping addAttributeMappingsFromDictionary:@
@"uuid": @"uuid",
@"title": @"title",
@"description": @"challengeDescription",
@"icon": @"icon",
@"active_from": @"activeFrom",
@"active_to": @"activeTo",
@"trigger": @"trigger",
@"show_in_feed": @"showInFeed",
@"points": @"points",
@"trigger": @"trigger",
@"type": @"type",
@"min_level": @"minLevel"
];
challengesMapping.identificationAttributes = @[ @"uuid" ];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:challengesMapping
pathPattern:CHALLENGE_PATH
keyPath:@"challenges"
statusCodes:[NSIndexSet indexSetWithIndex:SUCCESS]];
[objectManager addResponseDescriptor:responseDescriptor];
RKObjectMapping *sessionMapping = [RKObjectMapping mappingForClass:[TimeStamp class]];
[sessionMapping addAttributeMappingsFromArray:@[@"ts"]];
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:sessionMapping
pathPattern:CHALLENGE_PATH
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
和
- (void)setupMapping
RKObjectManager *objectManager = [RKObjectManager sharedManager];
RKEntityMapping *festivalsMapping = [RKEntityMapping mappingForEntityForName:@"Festival" inManagedObjectStore:[objectManager managedObjectStore]];
[festivalsMapping addAttributeMappingsFromDictionary:@
@"uuid": @"uuid",
@"festival": @"festivalDescription",
@"start_ts": @"start_ts",
@"end_ts": @"end_ts",
@"title": @"title"
];
festivalsMapping.identificationAttributes = @[ @"uuid" ];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:festivalsMapping
pathPattern:GET_FESTIVALS_PATH
keyPath:@"festivals"
statusCodes:[NSIndexSet indexSetWithIndex:SUCCESS]];
[objectManager addResponseDescriptor:responseDescriptor];
RKObjectMapping* sessionMapping = [RKObjectMapping mappingForClass:[TimeStamp class]];
[sessionMapping addAttributeMappingsFromArray:@[@"ts"]];
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:sessionMapping
pathPattern:GET_FESTIVALS_PATH
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
第一个映射(挑战)的第一个服务器调用工作正常,但是当我调用第二个(节日映射)时,我收到错误:“无法从此 NSManagedObjectContext 的协调器访问对象的持久存储”。我知道这可能是 Core Data 中的线程问题,但我在代码中找不到原因。
我在控制台中得到以下信息:
(lldb) po $r0
错误:无法实现结构:无法读取 r0(实现)
执行时出错,无法 PrepareToExecuteJITExpression
(lldb) 寄存器读取
通用寄存器:
r4 = 0x00000000
r5 = 0x00066e95 MyAppmain + 1 at main.m:14
r6 = 0x00000000
r7 = 0x2fd9ccf8
r8 = 0x2fd9cd10
r10 = 0x00000000
r11 = 0x00000000
r12 = 0x00000148
sp = 0x2fd9ccd4
lr = 0x00066f09 MyApp
main + 117 在 main.m:16
pc = 0x00066f09 MyApp`main + 117 at main.m:16
cpsr = 0x00000010
5 个寄存器不可用。
编辑
这是服务/映射类之一的完整示例。我之前看到过类似的模式,即使用 GCD 单例。我也不认为 TimeStamp 根据下面的评论是重复的,因为 pathPatterns 是不同的。正确的?我确实尝试删除它们,但同样的问题。这是预期的,因为它们没有得到 Core Data 的支持
#import "ChallengeService.h"
static ChallengeService __strong *defaultService = nil;
#define CHALLENGE_PATH @"/api/challenges"
@implementation ChallengeService
+ (ChallengeService *)defaultService
static dispatch_once_t pred;
dispatch_once(&pred, ^
defaultService = [[self alloc] initWithPath:CHALLENGE_PATH];
[defaultService setupMapping];
);
return defaultService;
- (void)setupMapping
RKObjectManager *objectManager = [RKObjectManager sharedManager];
RKEntityMapping *challengesMapping = [RKEntityMapping mappingForEntityForName:@"Challenge" inManagedObjectStore:[objectManager managedObjectStore]];
[challengesMapping addAttributeMappingsFromDictionary:@
@"uuid": @"uuid",
@"title": @"title",
@"description": @"challengeDescription",
@"icon": @"icon",
@"active_from": @"activeFrom",
@"active_to": @"activeTo",
@"trigger": @"trigger",
@"show_in_feed": @"showInFeed",
@"points": @"points",
@"trigger": @"trigger",
@"type": @"type",
@"min_level": @"minLevel"
];
challengesMapping.identificationAttributes = @[ @"uuid" ];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:challengesMapping
pathPattern:CHALLENGE_PATH
keyPath:@"challenges"
statusCodes:[NSIndexSet indexSetWithIndex:SUCCESS]];
[objectManager addResponseDescriptor:responseDescriptor];
RKObjectMapping *sessionMapping = [RKObjectMapping mappingForClass:[TimeStamp class]];
[sessionMapping addAttributeMappingsFromArray:@[@"ts"]];
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:sessionMapping
pathPattern:CHALLENGE_PATH
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
- (void)getChallengesFromDate:(NSDate *)date
onSuccess:(DidSucceedBlock)successBlock
onError:(DidFailWithErrorBlock)failBlock
[defaultService getWithData:nil
fromDate:date
onLoad:^(id object)
successBlock(object);
onError:^(NSError *error)
failBlock(error);
];
【问题讨论】:
【参考方案1】:首先,您不能多次将同一个映射添加到同一个对象管理器。考虑使用多个不同的对象管理器(每组请求一个,即每个单例一个)或预先定义公共映射。
然后,在您的问题中添加有关何时创建和配置这些单例的详细信息。它们中的任何一个是在后台线程上运行还是在应用程序启动时预先完成所有配置。如果您知道应用在每次使用时都会使用所有配置,那么请提前做好所有事情,因为构建配置的成本很低。
您需要小心defaultService
,因为目前您会将访问器方法与静态变量混淆。在方法内部定义静态变量并将其命名为_defaultService
。然后,您应该将 setup 方法移动到 initWithPath
,因为它是初始化的一部分。确保您正确调用了访问器方法,并且您没有从后台线程调用它(至少是第一次,并且可能每次)。
【讨论】:
以上是关于使用 RestKit 导致核心数据崩溃的多个 RKResponseDescriptor的主要内容,如果未能解决你的问题,请参考以下文章