看来,这个错误已经出现了很多次了。这个问题最突出的答案似乎是
RestKit 0.20 — CoreData: error: Failed to call designated initializer on NSManagedObject class

但是,发布的解决方案对我不起作用。但是,让我们从头开始:

我想将文件上传到服务器。我想解析响应以确保已成功上传。如果没有,我稍后再试。我的模型为此目的有一个名为NSNumber *sentToServer的布尔变量(在CoreData中,BOOL保存为NSNumber)。

因为我不知道发送是否会成功,所以在通过RestKit发送实体之前,我总是先将其保存到CoreData模型中。

POST请求成功后,服务器将返回一个JSON字符串,如下所示:

{"id":14,"created":true}

请注意,当然,尚未在CoreData模型上设置ID,因此idcreated都是我的模型的新信息。

这是我的模型:

@interface Recording : NSManagedObject

@property (nonatomic, retain) NSString * audioFilePath;
@property (nonatomic, retain) NSDate * createdAt;
@property (nonatomic, retain) NSString * deviceId;
@property (nonatomic, retain) NSString * deviceType;
@property (nonatomic, retain) NSNumber * recordingId;
@property (nonatomic, retain) NSNumber * sentToServer;

@end

这是我的设置方法:

NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"HTRecording" ofType:@"momd"]];
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"AudioModel.sqlite"];
NSError *error = nil;

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                         [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                         [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

if (![managedObjectStore addSQLitePersistentStoreAtPath:storePath
                                 fromSeedDatabaseAtPath: nil
                                      withConfiguration:nil
                                                options:options
                                                  error:&error]) {
    NSAssert(NO, @"Managed object store failed to create persistent store coordinator: %@", error);
}
[managedObjectStore createManagedObjectContexts];

// Configure MagicalRecord to use RestKit's Core Data stack
[NSPersistentStoreCoordinator MR_setDefaultStoreCoordinator:managedObjectStore.persistentStoreCoordinator];
[NSManagedObjectContext MR_setRootSavingContext:managedObjectStore.persistentStoreManagedObjectContext];
[NSManagedObjectContext MR_setDefaultContext:managedObjectStore.mainQueueManagedObjectContext];

NSString *databaseUrl = @"http://localhost:3000";
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:databaseUrl]];
objectManager.managedObjectStore = managedObjectStore;
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;

// Setup mapping
RKEntityMapping* recordingRequestMapping = [RKEntityMapping mappingForEntityForName:@"Recording" inManagedObjectStore:managedObjectStore];
[recordingRequestMapping addAttributeMappingsFromDictionary:@{
 @"device_id": @"deviceId",
 @"device_type": @"deviceType"     }];

RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[recordingRequestMapping inverseMapping]
                                                                               objectClass:[Recording class]
                                                                               rootKeyPath:@"recording"];
[objectManager addRequestDescriptor:requestDescriptor];

RKEntityMapping* recordingResponseMapping = [RKEntityMapping mappingForEntityForName:@"Recording" inManagedObjectStore:managedObjectStore];
[recordingResponseMapping addAttributeMappingsFromDictionary:@{
 @"created": @"sentToServer",
 @"id": @"recordingId"}];
recordingResponseMapping.identificationAttributes = @[@"recordingId"];

RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:recordingResponseMapping
                                                                                   pathPattern:@"/audio.json"
                                                                                       keyPath:nil
                                                                                   statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

[objectManager addResponseDescriptor:responseDescriptor];

首先,这是一个令人惊讶的冗长的设置代码,它应该很常见(只是init RestKit和MagicalRecord)。但是我离题了...

整个上传过程运行良好。请求映射很好,所有内容(包括附件)都存储在服务器上。请注意,请求映射不包含文件,因为它们是通过多部分post方法发送的。同样,该部分工作正常。这是上传文件的代码:

RKObjectManager *manager = [RKObjectManager sharedManager];
NSMutableURLRequest *request;

request = [manager multipartFormRequestWithObject:recording
                                           method:RKRequestMethodPOST
                                             path:@"audio.json"
                                       parameters:nil
                        constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        [formData appendPartWithFileData:[[NSFileManager defaultManager] contentsAtPath:recording.audioFilePath]
                                    name:@"recording[audio]"
                                fileName:[recording.audioFilePath lastPathComponent]
                                mimeType:@"audio/m4a"];
    }];

RKObjectRequestOperation *operation = [manager objectRequestOperationWithRequest:request
                                                                         success:^(RKObjectRequestOperation *op, RKMappingResult *mapping) {
                                                                             NSLog(@"successfully saved file on the server");
                                                                         }
                                                                         failure:^(RKObjectRequestOperation *op, NSError *error){
                                                                             NSLog(@"some weird error");
                                                                         }];


[manager enqueueObjectRequestOperation:operation];

将响应映射到对象变得困难。如果没有匹配的响应映射,日志输出将包含一个错误,无法处理响应(意外)。但是,使用匹配的响应映射,应用程序将崩溃。这是堆栈跟踪:

#11 0x2f6482d6 in -[NSObject(NSKeyValueCoding) valueForKeyPath:] ()
#12 0x00113b9a in -[RKMappingOperation shouldSetValue:forKeyPath:usingMapping:] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.m:436
#13 0x00114e40 in -[RKMappingOperation applyAttributeMapping:withValue:] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.m:536
#14 0x00115fd4 in -[RKMappingOperation applyAttributeMappings:] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.m:577
#15 0x0011c988 in -[RKMappingOperation main] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.m:948
#16 0x2f655d0a in -[__NSOperationInternal _start:] ()
#17 0x0010cd5a in -[RKMapperOperation mapRepresentation:toObject:atKeyPath:usingMapping:metadata:] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m:256
#18 0x0010b6aa in -[RKMapperOperation mapRepresentation:atKeyPath:usingMapping:] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m:176
#19 0x0010ddc8 in -[RKMapperOperation mapRepresentationOrRepresentations:atKeyPath:usingMapping:] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m:314
#20 0x0010e552 in -[RKMapperOperation mapSourceRepresentationWithMappingsDictionary:] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m:359
#21 0x0010ee72 in -[RKMapperOperation main] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m:398
#22 0x2f655d0a in -[__NSOperationInternal _start:] ()
#23 0x00100e70 in -[RKObjectResponseMapperOperation performMappingWithObject:error:] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/Network/RKResponseMapperOperation.m:345
#24 0x000ff4e6 in -[RKResponseMapperOperation main] at /Users/earthnail/development/RestkitFileUpload/Pods/RestKit/Code/Network/RKResponseMapperOperation.m:297
#25 0x2f655d0a in -[__NSOperationInternal _start:] ()

调试器在SIGABRT中以[RKMappingOperation shouldSetValue:forKeyPath:usingMapping:]停止的行是:

id currentValue = [self.destinationObject valueForKeyPath:keyPath];

请注意,当我按照https://stackoverflow.com/a/13734348/487556中的建议设置断点时,从未达到该断点。这意味着响应映射的路径没有问题。

我可以想象这里发生了几件事:
  • RestKit假定还没有CoreData实体,并想要创建一个。这将导致重复的实体(这简直太可惜了!),但是仍然不会崩溃,因为模型的所有字段都是可选的。
  • RestKit尝试根据ID查找CoreData实体(因为这是标识符变量),但是ID尚未设置。
  • 还有别的东西...

  • 有什么建议么?

    最佳答案

    我知道距您提出要求已经有一段时间了,也许您已经找到了解决方法,但是我遇到了同样的情况并找到了解决方案。

    问题来自于在使用NSManagedObjects时使用objectRequestOperationWithRequest:success:failure:方法的事实。因此,RestKit尝试在映射操作期间实例化常规NSObject,这会导致崩溃。

    尝试改用managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:,情况应该会更好。

    关于ios - RestKit 0.20 — CoreData:错误:无法再次调用NSManagedObject类上的指定初始化程序,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18258698/

    10-13 09:21