RestKit: как разместить массив объектов? - PullRequest
17 голосов
/ 11 октября 2011

Сводка вопроса:

Рассмотрим класс SyncObject, который соответствует KVC со свойствами, такими как: time, someValue, lastChange, uuid.

Рассмотрим NSArray, содержащий исключительно экземпляры SyncObject.

Мне нужно отправить массив на сервер в виде массива JSON.

Как можно отправить этомассив на сервер с помощью HTTP POST с использованием RestKit?

Пример массива:

[
  {
    "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 для получения JSON, который я могу POST на сервер.

Итак, создав массив и настроив сопоставление для класса объектов, хранящихся в массиве, я, естественно, пытаюсь 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*/];

ОднакоВот что я выхожу:

2011-10-11 14:57:51.769 AppConnect[1974:6e0b] *** Terminating app due to uncaught exception '(null)', reason: 'Unable to find a routable path for object of type '__NSArrayI' for HTTP Method '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];

К сожалению, это не относится ни к какому отображению, а вместо этого передает массив описаний объектов.Настройка 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: .

Ответы [ 2 ]

18 голосов
/ 11 октября 2011

Restkit не финансирует маршрутизируемый путь для NSArray, потому что вы определили свою маршрутизацию для класса NSManagedObject.Возможно, вы захотите создать собственный класс, скажем, MySyncEntity, который содержит ивы, которые вы определили в своем отображении.Затем вы создаете свое отображение следующим образом:

RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[MySyncEntity class]];
....
[myManager setSerializationMIMEType:RKMIMETypeJSON];
[[myManager router] routeClass:[MySyncEntity class] toResourcePath:@"/sync"];

, после чего вы сможете отправить свой объект в бэкэнд API как объект JSON.

Дополнительные пояснения:

В этом случае мы хотим опубликовать массив NSManagedObject экземпляров в API на основе JSON.Для этого нам нужно создать синхронизирующую сущность, которая содержит объекты в массиве:

@interface MySyncEntity : NSObject {}
@property (nonatomic, retain) NSArray* mySyncArray;
...
@end 

mySyncArray будет содержать полезную нагрузку, которую мы хотели бы передать остальному бэкэнду.Затем мы создаем соответствующее отображение как для NSManagedObject, которое будет отправлено в mySyncArray, так и для самой сущности MySyncEntity.

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 и отправлено в определенную конечную точку отдыха.

3 голосов
/ 12 октября 2011

В качестве дополнительного пояснения я хотел бы отметить, что в ответе mja ключевой момент -

[syncEntityMapping mapKeyPath:@"mySyncArray" toRelationship:@"mySyncArray" withMapping:mngObjMapping];

Это говорит о том, что «mySyncArray keypath - это массив, который содержит объекты, которые должны отображаться в соответствии с mngObjMapping».

...