1. 使用

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

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

1
2
3
4
5
6
7
8
9
10
11
@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, 这个类型如下定义:

1
2
3
4
5
6
7
8
9
@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类型创建一个复杂的对象,其中包含非对象属性,对象属性,还有包含对象的数组和字典。代码如下:

1
2
3
4
5
6
7
8
9
10
11
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变量)的字典:

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

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
     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数据

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

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
   "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

1
2
3
4
5
6
7
8
9
10
11
12
13
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#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
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐