iOS:把对象直接转化成NSDictionary或JSON
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
|