基于 NSObject 的类的 iOS JSON 序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10515015/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:18:01  来源:igfitidea点击:

iOS JSON serialization for NSObject-based classes

objective-ciosjsonserializationnsobject

提问by Journeyman

I'd like to JSON-serialize my own custom classes. I'm working in Objective-C / iOS5. I'd like something to do the following:

我想对我自己的自定义类进行 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]];

It seems that NSJSONSerialization (and several other libraries) require the 'person' class to be based on NSDictionary etc. I want something that will serialize any custom object that I care to define (within reason).

似乎 NSJSONSerialization(和其他几个库)要求“person”类基于 NSDictionary 等。我想要一些可以序列化我想定义的任何自定义对象的东西(在合理范围内)。

Let's imagine Person.h looks like this:

让我们想象一下 Person.h 看起来像这样:

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

I'd like the generated JSON for an instance to look similar to the following:

我希望为实例生成的 JSON 类似于以下内容:

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

My app uses ARC. I need something that will both serialise and deserialize using objects.

我的应用程序使用 ARC。我需要一些可以使用对象序列化和反序列化的东西。

Many thanks.

非常感谢。

回答by SushiGrass Jacob

This is a tricky one because the only data you can put into JSON are straight up simple objects (think NSString, NSArray, NSNumber…) but not custom classes or scalar types. Why? Without building all sorts of conditional statements to wrap all of those data types into those type of objects, a solution would be something like:

这是一个棘手的问题,因为您可以放入 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];

This is tricky, though because of what I stated before. If you have any scalar types or custom objects, the whole thing comes tumbling down. If it's really critical to get something like this going, I'd suggest looking into investing the time and looking at Ricard's links which allow you to see property types which would assist on the conditional statements needed to wrap the values into NSDictionary-safe objects.

这很棘手,尽管因为我之前说过。如果你有任何标量类型或自定义对象,整个事情就会崩溃。如果让这样的事情发生真的很重要,我建议你花时间看看 Ricard 的链接,它允许你查看属性类型,这些属性类型有助于将值包装到 NSDictionary 安全对象中所需的条件语句。

回答by X Sham

Now you can solve this problem easily using JSONModel. JSONModel is a library that generically serialize/deserialize your object based on Class. You can even use non-nsobject based for property like int, shortand float. It can also cater nested-complex JSON.

现在您可以使用JSONModel轻松解决这个问题。JSONModel 是一个基于 Class 对您的对象进行一般序列化/反序列化的库。您甚至可以将基于非 nsobject 的属性用于int,shortfloat。它还可以满足嵌套复杂的 JSON。

Deserialize example. By referring to your example, in header file:

反序列化例子。通过参考您的示例,在头文件中:

#import "JSONModel.h"

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

in implementation file:

在实现文件中:

#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):
}

Serialize Example. In implementation file:

序列化示例。在实现文件中:

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

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

NSLog(@"%@", [person toJSONString]);

回答by Joshua

maybe this can help JLObjectStrip.

也许这可以帮助JLObjectStrip

its the same as what jacob said but it iterates even to the property of the class. this will give you dictionary/array then just use sbjson/jsonkit or what ever you prefer to construct your json string.

它与雅各布所说的相同,但它甚至迭代到类的属性。这将为您提供字典/数组,然后只需使用 sbjson/jsonkit 或您喜欢构造 json 字符串的任何内容。

回答by Burrows Wang

Try this one BWJSONMatcher

试试这个BWJSONMatcher

It's really simple as well as convenient.

这真的很简单也很方便。

...
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];
...

回答by Travis Delly

What i do for my objects is i have a method called "toDict" that return a nsdictionary. IN this method i set all attributes i need/want into the dictionary for example

我为我的对象做的是我有一个名为“toDict”返回一个NSDictionary的方法。在这种方法中,我将我需要/想要的所有属性设置到字典中,例如

[user setObject:self.first_name forKey:@"first_name"];
[user setObject:self.last_name forKey:@"last_name"];
[user setObject:self.email forKey:@"email"];