Подтвердить что ты не робот

RestKit: Как разместить массив объектов?

Резюме вопроса:

Рассмотрим класс 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 s.

Как разместить массив объектов с помощью 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: .
4b9b3361

Ответ 1

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

Ответ 2

В качестве дополнительного разъяснения я хотел бы указать, что в mja answer ключевое слово

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

Это говорит о том, что "ключевой путь mySyncArray - это массив, содержащий объекты, которые должны отображаться в соответствии с mngObjMapping".