RestKit:如何发布一个对象数组?
问题摘要:
考虑一个与KVC兼容的类SyncObject
,例如: time
, someValue
, lastChange
, uuid
。
考虑只包含SyncObject
实例的NSArray
。
我需要将数组作为JSON数组提交给服务器。
如何使用RestKit使用HTTP POST将这个数组提交给服务器?
示例数组:
[ { "time": "14:45 10/21/2011", "someValue": "15", "lastChange": "14:45 10/21/2011", "uuid": "0b07c510-f4c8-11e0-be50-0800200c9a66" }, { "time": "14:50 10/21/2011", "someValue": "62", "lastChange": "14:51 10/21/2011", "uuid": "1a6d4480-f4c8-11e0-be50-0800200c9a66" } ]
细节
我有一个对象的数组,我需要作为JSON的服务器。 在我看来,RestKit是这样做的最简单的方法:我试图避免将对象转换成一组NSDictionary
对象,然后使用一些JSON编码器来获取我可以POST
到服务器的JSON。
所以,创build了数组,并设置了存储在数组中的对象类的映射,我自然会尝试POST
到服务器。
RKObjectManager* mgr = [RKObjectManager objectManagerWithBaseURL:@"http://localhost/someweb/api/"]; mgr.serializationMIMEType = RKMIMETypeFormURLEncoded; mgr.client.username = @"username"; mgr.client.password = @"password"; RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]]; [mapping mapKeyPath: @"time" toAttribute:@"time" ]; [mapping mapKeyPath: @"someValue" toAttribute:@"someValue" ]; [mapping mapKeyPath: @"lastChange" toAttribute:@"lastChange" ]; [mapping mapKeyPath: @"uuid" toAttribute:@"uuid" ]; RKObjectMapping* mappingForSerialization = [mapping inverseMapping]; [mgr.mappingProvider setSerializationMapping:mappingForSerialization forClass:[NSManagedObject class]]; [mgr.router routeClass:[NSManagedObject class] toResourcePath:@"/sync" forMethod:RKRequestMethodPOST]; [mgr postObject:array delegate:nil/*self*/];
但是,这是我得到的:
由于未捕获exception'(null)',终止应用程序AppConnect [1974:6e0b],原因:'无法findtypes为'__NSArrayI'的对象的可路由path用于HTTP方法'POST'”
显然,RestKit不知道如何处理NSArray
。
如何使用RestKit发布对象数组?
我尝试了一些不同的东西:我用RKObjectLoader
手动发送了最后一行。
//[mgr postObject:[NSMutableDictionary dictionaryWithObject:array forKey:@"data"] delegate:nil/*self*/]; NSString* syncPath = @"/sync"; RKObjectLoader * objectLoader = [mgr objectLoaderWithResourcePath:syncPath delegate:self]; objectLoader.serializationMIMEType = RKMIMETypeJSON; objectLoader.method = RKRequestMethodPOST; //objectLoader.objectClass = [NSManagedObject class]; //objectLoader.managedObjectStore = mgr.objectStore; objectLoader.params = [NSDictionary dictionaryWithObject:array forKey:@"MyData"]; [objectLoader send];
不幸的是,这不适用于任何types的映射,而是传输一组对象的描述。 设置serializationMIMEType
也不会影响传输内容的结构, params
总是作为application/x-www-form-urlencoded
来传输的。
我也尝试分配序列化映射,并将对象作为targetObject
和sourceObject
传递(这似乎是RestKit在内部在-[RKObjectManager postObject:delegate:]
)。
RKObjectLoader * objectLoader = [mgr objectLoaderWithResourcePath:syncPath delegate:self]; objectLoader.method = RKRequestMethodPOST; //objectLoader.objectClass = [NSManagedObject class]; //objectLoader.managedObjectStore = mgr.objectStore; objectLoader.params = [NSMutableDictionary dictionaryWithObject:array forKey:@"MyData"]; objectLoader.serializationMapping = mapping; objectLoader.serializationMIMEType = RKMIMETypeJSON; objectLoader.sourceObject = objectLoader.params; objectLoader.targetObject = objectLoader.params; [objectLoader send];
不幸的是,这种方式没有映射:
2011-10-12 12:36:48.143 MyProject[5119:207] D restkit.network:RKObjectLoader.m:290 POST or PUT request for source object { MyData = ( "<NSManagedObject: 0x5935430> (entity: SomeRecord; id: 0x5934da0 <x-coredata://64DF9977-DA50-4FCD-8C20-4132E58439BF/SomeRecord/p1> ; data: <fault>)", "<NSManagedObject: 0x5935730> (entity: SomeRecord; id: 0x5934db0 <x-coredata://64DF9977-DA50-4FCD-8C20-4132E58439BF/SomeRecord/p2> ; data: <fault>)" ); }, serializing to MIME Type application/json for transport... 2011-10-12 12:36:48.143 MyProject[5119:207] D restkit.object_mapping:RKObjectMappingOperation.m:428 Starting mapping operation... 2011-10-12 12:36:48.145 MyProject[5119:207] T restkit.object_mapping:RKObjectMappingOperation.m:291 Did not find mappable attribute value keyPath 'time' 2011-10-12 12:36:48.145 MyProject[5119:207] T restkit.object_mapping:RKObjectMappingOperation.m:291 Did not find mappable attribute value keyPath 'someValue' 2011-10-12 12:36:48.145 MyProject[5119:207] T restkit.object_mapping:RKObjectMappingOperation.m:291 Did not find mappable attribute value keyPath 'lastChange' 2011-10-12 12:36:48.145 MyProject[5119:207] T restkit.object_mapping:RKObjectMappingOperation.m:291 Did not find mappable attribute value keyPath 'uuid' 2011-10-12 12:36:48.145 MyProject[5119:207] D restkit.object_mapping:RKObjectMappingOperation.m:448 Mapping operation did not find any mappable content 2011-10-12 12:36:48.146 MyProject[5119:207] T restkit.network:RKRequest.m:211 Prepared POST URLRequest '<NSMutableURLRequest http://someurl/api/sync?request=provide_key>'. HTTP Headers: { Accept = "application/json"; "Content-Length" = 0; }. HTTP Body: .
restkit不资助NSArray的可路由path,因为你为NSManagedObject
类定义了路由。 你可能想要创build一个自定义的类,比如MySyncEntity
,它包含你在映射中定义的ivars。 然后,你创build你的映射像这样:
RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[MySyncEntity class]]; .... [myManager setSerializationMIMEType:RKMIMETypeJSON]; [[myManager router] routeClass:[MySyncEntity class] toResourcePath:@"/sync"];
那么你应该能够把你的对象作为JSON对象发布到API后端。
进一步澄清:
在这种情况下,我们想要将一个NSManagedObject
实例数组放入基于JSON的API中。 要做到这一点,我们需要创build一个同步实体,它包含一个数组中的对象:
@interface MySyncEntity : NSObject {} @property (nonatomic, retain) NSArray* mySyncArray; ... @end
mySyncArray
将保存我们想要提交给其余后端的负载。 然后,我们为将在mySyncArray
发送的mySyncArray
和MySyncEntity
实体本身创build适当的映射。
RKObjectManager *manager = [RKObjectManager objectManagerWithBaseURL:kBaseUrl]; ... RKObjectMapping *mngObjMapping = [RKObjectMapping mappingForClass:[NSManagedObject class]]; [mngObjMapping mapKeyPath: @"time" toAttribute:@"time"]; [mngObjMapping mapKeyPath: @"recordLevel" toAttribute:@"recordLevel"]; .... //map as many properties as you wish [[manager mappingProvider] setSerializationMapping:[mngObjMapping inverseMapping] forClass:[NSManagedObject class]]; //now, we create mapping for the MySyncEntity RKObjectMapping *syncEntityMapping = [RKObjectMapping mappingForClass:[MySyncEntity class]]; [syncEntityMapping mapKeyPath:@"mySyncArray" toRelationship:@"mySyncArray" withMapping:mngObjMapping]; [[manager mappingProvider] setSerializationMapping:[syncEntityMapping inverseMapping] forClass:[MySyncEntity class]];
现在通过定义的映射,我们可以将对象发布到服务器
[manager postObject:mySyncInstance delegate:nil];
mySyncInstance
数组的内容将根据mngObjMapping
映射mngObjMapping
送到定义的rest端点。
作为进一步的澄清,我想指出,在mja的答案中 ,关键是
[syncEntityMapping mapKeyPath:@"mySyncArray" toRelationship:@"mySyncArray" withMapping:mngObjMapping];
这说“ mySyncArray
keypath是一个数组,其中包含应根据mngObjMapping
映射的对象”。