RestKit RKObjectMapping для CLLocation

#ios #json #mapping #restkit #cllocation

#iOS #json #отображение #набор для отдыха #cllocation #restkit

Вопрос:

Я использую объектное сопоставление RestKit для сопоставления данных JSON с объектом. Возможно ли сопоставить атрибуты JSON широты и долготы с CLLocation переменной в моем классе Objective-C?

JSON:

 { "items": [
    {
        "id": 1,
        "latitude": "48.197186",
        "longitude": "16.267452"
    },
    {
        "id": 2,
        "latitude": "48.199615",
        "longitude": "16.309645"
    }
]
  

}

Класс, к которому он должен быть сопоставлен:

 @interface ItemClass : NSObject    
  @property (nonatomic, strong) CLLocation *location;
@end
  

В конце я хотел бы вызвать itemClassObj.location.longitude получение значения широты из ответа JSON.

Я думал, что что-то подобное сработает, но это не так.

 RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[ItemClass class]];
[mapping mapKeyPath:@"latitude" toAttribute:@"location.latitude"];
[mapping mapKeyPath:@"longitude" toAttribute:@"location.longitude"];
  

Большое спасибо за вашу помощь.

Ответ №1:

RestKit добавил ValueTransformer специально для CLLocation:

https://github.com/RestKit/RKCLLocationValueTransformer

Учитывая пример JSON:

 {
    "user": {
        "name": "Blake Watters",
        "location": {
            "latitude": "40.708",
            "longitude": "74.012"
        }
    }
}
  

Для сопоставления из заданного JSON с пользовательским объектом:

 @interface User : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) CLLocation *location;
@end
  

Используйте RKCLLocationValueTransformer:

 #import "RKCLLocationValueTransformer.h"

RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[User class]];
[userMapping addAttributeMappingsFromArray:@[ @"name" ]];
RKAttributeMapping *attributeMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"location" toKeyPath:@"location"];
attributeMapping.valueTransformer = [RKCLLocationValueTransformer locationValueTransformerWithLatitudeKey:@"latitude" longitudeKey:@"longitude"];
[userMapping addPropertyMapping:attributeMapping];

RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"user" statusCodes:[NSIndexSet indexSetWithIndex:200]];
  

Ответ №2:

Для создания CLLocation вам нужны одновременно широта и долгота. Более того, координаты для CLLocation (например, CLLocationCoordinate2D) не являются NSNumbers, они являются двойными числами с плавающей точкой, поэтому он может повысить соответствие ключевого значения при сопоставлении подобным образом, потому что числа с плавающей точкой не являются объектами.

Чаще всего люди сохраняют широту и долготу в классе как NSNumbers, а затем создают координату CLLocationCoordinate2D по требованию после создания экземпляра объекта класса / заполнения.

Что вы могли бы сделать, если бы были так склонны, это использовать метод willMapData: delegate для отслеживания поступающих данных, чтобы вручную заполнить CLLocation … но для меня это излишество и требует слишком больших накладных расходов.


РЕДАКТИРОВАТЬ: добавляю это, потому что комментарии не форматируют свойство кода…

Или вы могли бы поместить что-то подобное в реализацию вашего класса объектов и интерфейс…

 @property (nonatomic,readonly) CLLocationCoordinate2D coordinate;

- (CLLocationCoordinate2D)coordinate {
    CLLocationDegrees lat = [self.latitude doubleValue];
    CLLocationDegrees lon = [self.longitude doubleValue];
    CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(lat, lon);
    if (NO == CLLocationCoordinate2DIsValid(coord))
        NSLog(@"Invalid Centroid: lat=%lf lon=%lf", lat, lon);
    return coord;
}
  

Комментарии:

1. Есть ли метод, который срабатывает в моей модели, как только все сопоставлено? Тогда я мог бы просто присвоить отображенные значения lat amp; long значениям CLLocationCoordinate…

2. Почему бы не создать свойство только для чтения в вашей модели, которое сделает это за вас? Вы просто вызываете его всякий раз, когда будете готовы перенести его на карту… Поскольку комментарии не могут отформатировать код, стоящий черт знает чего, смотрите Мои правки выше.

3. Кроме того, я думаю, что касается прямого ответа на ваш вопрос после сопоставления, objectMapperDidFinishMapping: ?

4. Привет, спасибо… Да, сегодня утром я реализовал нечто похожее на ваш подход, и он работает как по маслу. Еще раз спасибо за вашу помощь.

5. Приятно слышать, и я рад помочь!