iOS: 把对象直接转化成NSDictionary或JSON

时间:2021-06-22 17:56:47

1. 使用

实现的结果就是可以把任何对象转化成字典或者字典对应的JSON。字典的数据就是来自对象的属性名称和属性值 。而且是多层的,也就是说如果对象的某个属性值是另一个对象,数组,或者字典,该值都会被转换成另一个字典。

这个类型名称是PrintObject,它的所有方法都是静态的:

1234567891011 @interface
PrintObject : NSObject
//通过对象返回一个NSDictionary,键是属性名称,值是属性值。+
(NSDictionary*)getObjectData:(id)obj;
  //将getObjectData方法返回的NSDictionary转化成JSON+
(NSData*)getJSON:(id)obj options:(NSJSONWritingOptions)options error:(NSError**)error;
  //直接通过NSLog输出getObjectData方法返回的NSDictionary+
(void)print:(id)obj;
  @end

举个例子,比如用来保存数据的类型是MyData, 这个类型如下定义:

123456789 @interface
MyData : NSObject
@property
(nonatomic, strong) NSString *name;
@property
(nonatomic, strong) NSString *nullString;
@property
(nonatomic) int age;
@property
(nonatomic) BOOL male;
@property
(nonatomic, strong) MyData *objProp;
@property
(nonatomic, strong) NSArray *arrProp;
@property
(nonatomic, strong) NSDictionary *dicProp;
@end

然后通过MyData类型创建一个复杂的对象,其中包含非对象属性,对象属性,还有包含对象的数组和字典。代码如下:

1234567891011 MyData
*main = [[MyData alloc] init];
main.name
= @
"mgen";
main.age
= 22;
MyData
*childOfChild = [[MyData alloc] init];
childOfChild.name
= @
"child of child";
childOfChild.age
= -443;
MyData
*child = [[MyData alloc] init];
child.name
= @
"child";
child.arrProp
= @[@
"test", @234, @[@123, @"array in array", childOfChild]];
main.objProp
= child;
main.dicProp
= @{@
"中文Key": @3.444444, @"object": childOfChild};

OK,接着使用PrintObject类型输出这个MyData对象(上面的main变量)的字典:

12 NSDictionary
*dic = [PrintObject getObjectData:main];
NSLog(@"%@", dic);

输出:

1234567891011121314151617181920212223242526272829303132333435363738394041424344 {    age = 22;    arrProp = "<null>";    dicProp =     {        object =         {            age = "-443";            arrProp = "<null>";            dicProp = "<null>";            male = 0;            name = "child of child";            nullString = "<null>";            objProp = "<null>";        };        "\U4e2d\U6587Key"
=
"3.444444";
    };    male = 0;    name = mgen;    nullString = "<null>";    objProp =     {        age = 0;        arrProp =         (            test,            234,                        (                123,                "array in array",                                {                    age = "-443";                    arrProp = "<null>";                    dicProp = "<null>";                    male = 0;                    name = "child of child";                    nullString = "<null>";                    objProp = "<null>";                }            )        );        dicProp = "<null>";        male = 0;        name = child;        nullString = "<null>";        objProp = "<null>";    };}

也可以输出这个对象的JSON数据

123 NSData
*jsonData = [PrintObject getJSON:main options:NSJSONWritingPrettyPrinted error:nil];
NSString
*jsonText = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(@"%@", jsonText);

结果:

1234567891011121314151617181920212223242526272829303132333435363738394041424344 {  "arrProp"
:
null,
  "name"
:
"mgen",
  "age"
: 22,
  "objProp"
: {
    "arrProp"
: [
      "test",      234,      [        123,        "array in array",        {          "arrProp"
:
null,
          "name"
:
"child of child",
          "age"
: -443,
          "objProp"
:
null,
          "male"
: 0,
          "nullString"
:
null,
          "dicProp"
:
null
        }      ]    ],    "name"
:
"child",
    "age"
: 0,
    "objProp"
:
null,
    "male"
: 0,
    "nullString"
:
null,
    "dicProp"
:
null
  },  "male"
: 0,
  "nullString"
:
null,
  "dicProp"
: {
    "中文Key"
: 3.444444,
    "object"
: {
      "arrProp"
:
null,
      "name"
:
"child of child",
      "age"
: -443,
      "objProp"
:
null,
      "male"
: 0,
      "nullString"
:
null,
      "dicProp"
:
null
    }  }}

2. 实现

在实现上,属性的枚举是通过定义在<objc/runtime.h>中的class_copyPropertyList方法实现。其次,属性值的获取是通过KVC中的valueForKey方法,这个方法同时可以将非对象类型(如BOOL, int等)转换成NSNumber。

接着就是对数组,字典和对象类型值的嵌套处理,所有值就可以获取出来了。

至于JSON,如果正确获取了NSDictionary后,直接使用iOS 5后的NSJSONSerialization类型的dataWithJSONObject方法就可以返回包含JSON字符串的NSData对象了。

3. 下载和代码

源代码下载 下载页面 

注意:链接是微软SkyDrive页面,下载时请用浏览器直接下载,用某些下载工具可能无法下载 

源代码环境:Xcode 4.6.3

PrintObject.h

12345678910111213 #import
<Foundation/Foundation.h>
  @interface
PrintObject : NSObject
//通过对象返回一个NSDictionary,键是属性名称,值是属性值。+
(NSDictionary*)getObjectData:(id)obj;
  //将getObjectData方法返回的NSDictionary转化成JSON+
(NSData*)getJSON:(id)obj options:(NSJSONWritingOptions)options error:(NSError**)error;
  //直接通过NSLog输出getObjectData方法返回的NSDictionary+
(void)print:(id)obj;
  @end

PrintObject.m

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 #import
"PrintObject.h"
#import
<objc/runtime.h>
  @implementation
PrintObject
  +
(NSDictionary*)getObjectData:(id)obj
{    NSMutableDictionary *dic = [NSMutableDictionary dictionary];    unsigned int propsCount;    objc_property_t *props = class_copyPropertyList([obj class], &propsCount);    for(int i = 0;i < propsCount; i++)    {        objc_property_t prop = props[i];                NSString *propName = [NSString stringWithUTF8String:property_getName(prop)];        id value = [obj valueForKey:propName];        if(value == nil)        {            value = [NSNull null];        }        else        {            value = [self getObjectInternal:value];        }        [dic setObject:value forKey:propName];    }    return
dic;
}  +
(void)print:(id)obj
{    NSLog(@"%@", [self getObjectData:obj]);}    +
(NSData*)getJSON:(id)obj options:(NSJSONWritingOptions)options error:(NSError**)error
{    return
[NSJSONSerialization dataWithJSONObject:[self getObjectData:obj] options:options error:error];
}  +
(id)getObjectInternal:(id)obj
{    if([obj isKindOfClass:[NSString class]]       || [obj isKindOfClass:[NSNumber class]]       || [obj isKindOfClass:[NSNull class]])    {        return
obj;
    }        if([obj isKindOfClass:[NSArray class]])    {        NSArray *objarr = obj;        NSMutableArray *arr = [NSMutableArray arrayWithCapacity:objarr.count];        for(int i = 0;i < objarr.count; i++)        {            [arr setObject:[self getObjectInternal:[objarr objectAtIndex:i]] atIndexedSubscript:i];        }              return
arr;
    }        if([obj isKindOfClass:[NSDictionary class]])    {        NSDictionary *objdic = obj;        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:[objdic count]];        for(NSString *key in
objdic.allKeys)
        {            [dic setObject:[self getObjectInternal:[objdic objectForKey:key]] forKey:key];        }             return
dic;
        return
[self getObjectData:obj];
}  @end