Сериализация iOS JSON для классов на основе NSObject

Я хотел бы сериализовать свои собственные классы в формате JSON. Я работаю в Objective-C / iOS5. Я бы хотел сделать следующее:

Person* person = [self getPerson ]; // Any custom object, NOT based on NSDictionary
NSString* jsonRepresentation = [JsonWriter stringWithObject:person ];
Person* clone = [JsonReader objectFromJson: jsonRepresentation withClass:[Person Class]];

Кажется, что NSJSONSerialization (и несколько других библиотек) требуют, чтобы класс «person» был основан на NSDictionary и т. Д. Я хочу что-то, что будет сериализовать любой настраиваемый объект, который я хочу определить (в пределах разумного).

Представим, что Person.h выглядит так:

#import <Foundation/Foundation.h>
@interface Person : NSObject 
@property NSString* firstname;
@property NSString* surname;
@end

Я бы хотел, чтобы сгенерированный JSON для экземпляра выглядел примерно так:

{"firstname":"Jenson","surname":"Button"}

Мое приложение использует ARC. Мне нужно что-то, что будет сериализовать и десериализовать с помощью объектов.

Большое спасибо.


person Journeyman    schedule 09.05.2012    source источник
comment
Если бы вы могли получить список атрибутов, вы могли бы перебирать их, вызывая метод valueForKey:, чтобы получить его содержимое и заполнить словарь ... Кажется, вы сможете сделать это с помощью class_copyPropertyList () и некоторых других странных методов. Это может помочь: stackoverflow.com/questions/754824/ Удачи!   -  person Ricard Pérez del Campo    schedule 09.05.2012
comment
Эта ссылка поможет вам ..... http://stackoverflow.com/a/29095726/3177007   -  person Mohamed Jaleel Nazir    schedule 17.03.2015


Ответы (5)


Это сложно, потому что единственные данные, которые вы можете поместить в JSON, - это простые объекты (подумайте о NSString, NSArray, NSNumber…), но не пользовательские классы или скалярные типы. Почему? Без создания всевозможных условных операторов для обертывания всех этих типов данных в объекты этого типа решение будет примерно таким:

//at the top…
#import <objC/runtime.h>

    NSMutableDictionary *muteDictionary = [NSMutableDictionary dictionary];

    id YourClass = objc_getClass("YOURCLASSNAME");
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(YourClass, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        SEL propertySelector = NSSelectorFromString(propertyName);
        if ([classInstance respondsToSelector:propertySelector]) {
            [muteDictionary setValue:[classInstance performSelector:propertySelector] forKey:propertyName];
        }
    }
    NSError *jsonError = nil;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:muteDictionary options:0 error:&jsonError];

Это сложно, хотя из-за того, что я уже говорил ранее. Если у вас есть какие-либо скалярные типы или настраиваемые объекты, все рушится. Если действительно важно добиться чего-то подобного, я бы посоветовал потратить время и посмотреть ссылки Рикара, которые позволяют увидеть типы свойств, которые помогут в условных операторах, необходимых для обертывания значений в объекты, безопасные для NSDictionary.

person SushiGrass Jacob    schedule 09.05.2012
comment
спасибо за это, и спасибо Рикарду тоже. Мне удалось создать решение, построенное после вашего первоначального управления. - person Journeyman; 14.05.2012
comment
Прекрасная работа! Надеюсь яблоко не забанит. - person Dumoko; 17.04.2013
comment
Библиотека, предложенная Малькольмом ниже, уже делает это за вас. - person Marin Todorov; 19.09.2013

Теперь вы можете легко решить эту проблему с помощью JSONModel. JSONModel - это библиотека, которая в целом сериализует / десериализует ваш объект на основе класса. Вы даже можете использовать объекты, отличные от nsobject, для таких свойств, как int, short и float. Он также может обслуживать вложенный сложный JSON.

Пример десериализации. Ссылаясь на ваш пример, в файле заголовка:

#import "JSONModel.h"

@interface Person : JSONModel 
@property (nonatomic, strong) NSString* firstname;
@property (nonatomic, strong) NSString* surname;
@end

в файле реализации:

#import "JSONModelLib.h"
#import "yourPersonClass.h"

NSString *responseJSON = /*from somewhere*/;
Person *person = [[Person alloc] initWithString:responseJSON error:&err];
if (!err)
{
   NSLog(@"%@  %@", person.firstname, person.surname):
}

Пример сериализации. В файле реализации:

#import "JSONModelLib.h"
#import "yourPersonClass.h"

Person *person = [[Person alloc] init];
person.firstname = @"Jenson";
person.surname = @"Uee";

NSLog(@"%@", [person toJSONString]);
person X Sham    schedule 27.05.2013
comment
Элегантное решение. Очень признателен. - person Joey Carson; 04.07.2015

возможно, это поможет JLObjectStrip.

это то же самое, что сказал Джейкоб, но повторяется даже свойство класса. это даст вам словарь / массив, а затем просто используйте sbjson / jsonkit или то, что вы предпочитаете, для создания своей строки json.

person Joshua    schedule 29.04.2013

Попробуйте этот BWJSONMatcher

Это действительно просто и удобно.

...
NSString *jsonString = @"{your-json-string}";
YourValueObject *dataModel = [YourValueObject fromJSONString:jsonString];

NSDictionary *jsonObject = @{your-json-object};
YourValueObject *dataModel = [YourValueObject fromJSONObject:jsonObject];
...
YourValueObject *dataModel = instance-of-your-value-object;
NSString *jsonString = [dataModel toJSONString];
NSDictionary *jsonObject = [dataModel toJSONObject];
...
person Burrows Wang    schedule 29.10.2015

Что я делаю для своих объектов, так это метод toDict, который возвращает nsdictionary. В этом методе я устанавливаю все атрибуты, которые мне нужны / хочу, например, в словарь

[user setObject:self.first_name forKey:@"first_name"];
[user setObject:self.last_name forKey:@"last_name"];
[user setObject:self.email forKey:@"email"];
person Travis Delly    schedule 25.11.2016