使用RestKit导致Core Data崩溃的多个RKResponseDescriptors

时间:2013-04-22 00:16:47

标签: ios core-data restkit

我在每个服务调用的单例中创建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)]];
}

第一个映射(challenge)的第一个服务器调用工作正常,但是当我进行第二个调用(节日映射)时,我得到错误:“无法从此NSManagedObjectContext的协调器访问对象的持久存储”。我理解这是Core Data中可能存在的线程问题,但我在代码中找不到原因。

我在控制台中收到以下信息:

(lldb)po $ r0 错误:无法实现struct:无法读取r0(实现) 在Execute中出错,无法PrepareToExecuteJITExpression (lldb)注册读取 通用寄存器:         r4 = 0x00000000         r5 = 0x00066e95在main.m上的MyApp main + 1 at main.m:14 r6 = 0x00000000 r7 = 0x2fd9ccf8 r8 = 0x2fd9cd10 r10 = 0x00000000 r11 = 0x00000000 r12 = 0x00000148 sp = 0x2fd9ccd4 lr = 0x00066f09 MyApp main + 117:16         pc = 0x00066f09 MyApp`main + 117 at main.m:16       cpsr = 0x00000010 5个寄存器不可用。

修改

以下是其中一个服务/映射类的完整示例。我看过之前使用的类似模式,即使用GCD单例。我也不认为TimeStamp对于下面的评论是重复的,因为pathPatterns是不同的。正确?我确实尝试删除它们,但同样的问题。这是预期的,因为它们没有核心数据支持

#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 个答案:

答案 0 :(得分:0)

首先,您不能多次向同一个对象管理器添加相同的映射。考虑使用多个不同的对象管理器(每个请求集一个,即每个单例一个)或预先定义公共映射。

然后,在您的问题中添加有关何时创建和配置每个单例的详细信息。它们中的任何一个是在后台线程上运行还是在应用程序启动时预先完成所有配置。如果您知道应用程序将在每次使用时使用所有配置,那么请事先做好所有事情,因为构建配置的成本很低。

您需要小心defaultService,因为目前您会将访问者方法与静态变量混淆。在方法中定义静态变量并将其命名为_defaultService。然后,您应该将设置方法移动到initWithPath,因为它是初始化的一部分。确保您正在正确调用访问器方法,并且您没有从后台线程调用它(至少第一次,可能每次都调用它)。