iOS RestKit问题:无效参数不满足:responseDescriptors

时间:2013-05-20 18:21:30

标签: ios xcode restkit

我正在尝试使用RestKit来检索事件列表,我一直这样做:

2013-05-20 10:52:56.708 EventApp[3380:c07] I restkit:RKLog.m:34 RestKit logging initialized...
2013-05-20 10:52:56.773 EventApp[3380:c07] *** Assertion failure in    -[RKObjectRequestOperation initWithRequest:responseDescriptors:], /Users/mitchell/Desktop/eventapp/take2/EventApp/Pods/RestKit/Code/Network/RKObjectRequestOperation.m:158
2013-05-20 10:52:56.774 EventApp[3380:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: responseDescriptors' 

我在这个问题上已经好几天了。由于我的iOS开发技能(每年大约一个项目)存在相当大的差距,如果有人能够使用一些非专业术语引导我朝着正确的方向前进,那将会非常有帮助。

请考虑我特意使用enqueueObjectRequestOperation来批量处理多个请求。我在这里拼凑了一些代码用于翻译。

这是我的数据模型的样子:

Here is what my datamodel looks like:

以下是JSON文件的样子:

[{
"id":1,
"farm_id":1,
"all_day": "NO",
"from": "2013-05-08T18:45:38Z",
"to": "2013-05-08T18:45:38Z",
"name": "event 1",
"desc": "some description",
"photo": "some.png",
"price": "price"
}]

这是我的代码:

NSManagedObjectContext *context;

RKObjectManager *objectManager;
if (self.eventContext == nil) {
    NSError *error = nil;
    NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"FarmApp" ofType:@"momd"]];
    RKEntityMapping *entityMapping;
    // NOTE: Due to an iOS 5 bug, the managed object model returned is immutable.
    NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];

    RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];

    // Initialize the Core Data stack
    [managedObjectStore createPersistentStoreCoordinator];

    NSPersistentStore __unused *eventPersistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
    NSAssert(eventPersistentStore, @"Failed to add persistent store: %@", error);

    [managedObjectStore createManagedObjectContexts];

    // Set the default store shared instance
    [RKManagedObjectStore setDefaultStore:managedObjectStore];

    // Configure the object manager
    RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://sandbox.bm.com"]];

    [RKObjectManager setSharedManager:objectManager];

    [objectManager setRequestSerializationMIMEType:@"application/json"];
    [objectManager setAcceptHeaderWithMIMEType:@"text/plain"];

    objectManager.managedObjectStore = managedObjectStore;
        entityMapping = [RKEntityMapping mappingForEntityForName:@"Event" inManagedObjectStore:managedObjectStore];
        [entityMapping addAttributeMappingsFromDictionary:@{
         @"id":             @"eventID",
         @"farm_id":        @"farm",
         @"all_day":        @"allDay",
         @"from":           @"from",
         @"to":             @"to",
         @"name":           @"name",
         @"desc":           @"desc",
         @"photo":          @"photo",
         @"price":          @"price"
         }];        
    RKResponseDescriptor *successDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

    [objectManager addResponseDescriptor:successDescriptor];

    RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:@"errors" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];

    [objectManager addResponseDescriptor:errorDescriptor];
    self.eventContext = managedObjectStore.mainQueueManagedObjectContext;

}
context = self.eventContext;
NSString* url = [NSString stringWithFormat:@"http://sandbox.bm.com/farmapp/%@.json", @"events"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:[objectManager responseDescriptors]];
[operation setCompletionBlockWithSuccess:nil failure:^(RKObjectRequestOperation *operation, NSError *error) {
    NSLog(@"Loaded this error: %@", [error localizedDescription]);
}];
NSArray *operations = [NSArray arrayWithObjects:operation, nil];
for (int i = 0; i < [operations count]; i++ ) {
    [[RKObjectManager sharedManager] enqueueObjectRequestOperation:[operations objectAtIndex:i]];
}

有人可以帮助我吗?

以下是最终解决方案

if (self.eventContext == nil) {
    NSManagedObjectContext *context;
    RKObjectManager *objectManager;
    NSError *error = nil;
    NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"FarmApp" ofType:@"momd"]];
    RKEntityMapping *entityMapping;
    // NOTE: Due to an iOS 5 bug, the managed object model returned is immutable.
    NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];

    RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];

    // Initialize the Core Data stack
    [managedObjectStore createPersistentStoreCoordinator];

    NSPersistentStore __unused *eventPersistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
    NSAssert(eventPersistentStore, @"Failed to add persistent store: %@", error);

    [managedObjectStore createManagedObjectContexts];

    // Set the default store shared instance
    [RKManagedObjectStore setDefaultStore:managedObjectStore];

    // Configure the object manager
    objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://sandbox.bm.com"]];

    [RKObjectManager setSharedManager:objectManager];

    [objectManager setRequestSerializationMIMEType:@"application/json"];
    [objectManager setAcceptHeaderWithMIMEType:@"text/plain"];

    objectManager.managedObjectStore = managedObjectStore;
    entityMapping = [RKEntityMapping mappingForEntityForName:@"Event" inManagedObjectStore:managedObjectStore];
    [entityMapping addAttributeMappingsFromDictionary:@{
     @"id":             @"eventID",
     //@"farm_id":        @"farm",-->cannot create relationship this way
     @"farm_id" :       @"farmID",//farmID attribute needs to be added to Event's model
     @"all_day":        @"allDay",
     @"from":           @"from",
     @"to":             @"to",
     @"name":           @"name",
     @"desc":           @"desc",
     @"photo":          @"photo",
     @"price":          @"price"
     }];

    [entityMapping addConnectionForRelationship:@"farm" connectedBy:@"farmID"];

    RKResponseDescriptor *successDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:@"events" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

    [objectManager addResponseDescriptor:successDescriptor];

    RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:@"errors" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];

    [objectManager addResponseDescriptor:errorDescriptor];

    self.eventContext = managedObjectStore.mainQueueManagedObjectContext;
    context = self.eventContext;
    NSString* url = [NSString stringWithFormat:@"http://sandbox.bm.com/farmapp/%@.json", @"events"];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    RKManagedObjectRequestOperation *operation = [objectManager managedObjectRequestOperationWithRequest:request managedObjectContext:managedObjectStore.mainQueueManagedObjectContext success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
            NSLog(@"Success");
        } failure:^(RKObjectRequestOperation *operation, NSError *error) {
                NSLog(@"Failure");
        }];
    NSArray *operations = [NSArray arrayWithObjects:operation, nil];
    for (int i = 0; i < [operations count]; i++ ) {
        [[RKObjectManager sharedManager] enqueueObjectRequestOperation:[operations objectAtIndex:i]];
    }

}

2 个答案:

答案 0 :(得分:1)

作为@JoelH。在他的一条评论中建议,你需要使用RKManagedObjectRequestOperation而不是RKObjectRequestOperation。

例如:

RKManagedObjectRequestOperation *operation = [objectmanager managedObjectRequestOperationWithRequest:request managedObjectContext:managedObjectStore.mainQueueManagedObjectContext success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        NSLog(@"Success");
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        NSLog(@"Failure");
}];

此外,我认为你的映射方式

@"farm_id": @"farm"

不正确。

如果要构建Event和Farm之间的关系,则需要使用以下方法之一: relationshipMappingFromKeyPath:toKeyPath:withMapping:addConnectionForRelationship:connectedBy:

如果Farm对象已经存在而您只想映射新事件,我会选择addConnectionForRelationship:connectedBy:

例如:

RKEntityMapping* eventMapping = [RKEntityMapping mappingForEntityForName:@"Event" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:@{
 @"id":             @"eventID",
 //@"farm_id":        @"farm",-->cannot create relationship this way
 @"farm_id" :       @"farmID",//farmID attribute needs to be added to Event's model
 @"all_day":        @"allDay",
 @"from":           @"from",
 @"to":             @"to",
 @"name":           @"name",
 @"desc":           @"desc",
 @"photo":          @"photo",
 @"price":          @"price"
 }];

[eventMapping addConnectionForRelationship:@"farm" connectedBy:@"farmID"];   

还需要在事件模型中添加farmID属性,即RestKit does not allow relationship connection without intermediary attributes

答案 1 :(得分:0)

RestKit文档(Mapping Without KVC)似乎暗示如果您在顶层没有KVC标签(例如events:[]),则解析器需要pathPattern:知道要使用哪个映射。由于您keyPath:的{​​{1}}和pathPattern:nil,我有两个建议:

  1. 如果可以更改JSON结构,请将顶级更改为successDescriptor并将{ events:[...] }更改为keyPath:nil以反映此更改。

  2. 如果无法做到,请将keyPath:@"events"更改为pathPattern:nil注意,我设置pathPattern:@"/farmapp"以匹配您的资源网址。如果您还有从该URL分支的其他类型的资源,则第二个建议可能无效。

  3. 另外,我注意到您的pathPattern:使用与errorDescriptor相同的映射(entityMapping)。我不知道这是不是你想要的,但是如果你的错误响应应该是一些不同的错误对象,我建议改变它。

    希望这有帮助!