一种自动的将自定义类序列化为JSON的方法

转载 2012年03月22日 00:38:35

一种自动的将自定义类序列化为JSON的方法   

最近因为项目需求,需要将一些自定义的类序列化为JSON,网上有很多好用的第三方序列化工具,但都只能自动序列化一些基本类型,如NSNumber,NSString与NSDictionary这种,没有一种第三方工具提供直接将自定义类序列化的方法(至少据我所知:),而对于这种序列化自定义的类的需求,网上能查到的方法只有将自定义的类手动的转存为一个NSDictionary,然后再使用第三方工具来序列化。例如对于一个类Foo,有如下定义:
?
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
@interface Foo : NSObject
 
{
 
  NSString *_property1;
 
  NSString *_property2;
 
}
 
@property(nonatomic,retain)NSString *property1;
 
@property(nonatomic,retain)NSString *property2;
 
  
 
@implementation Foo
 
@synthesize property1 = _property1;
@synthesize property2 = _property2;
 
- (id)init
{
    self = [super init];
     
    if (self)
    {
        _property1 = @"haha";
        _property2 = @"hehe";
    }
 
    return self;
}
 
- (void)dealloc
 
{
 
  [super dealloc];
 
}


要序列化它的方法只有:

?
1
2
3
4
5
6
7
8
9
10
11
Foo *foo = [[Foo alloc] init];
 
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
 
                             foo.property1,@"property1",
 
                             foo.property2,@"property2",               
 
                                nil];
 
[[JSONSerializer serializer] serializer:dict];


这种方法的缺陷在于太不灵活,每一次序列化的时候都需要写很多重复的代码,上面的代码还没有考虑属性值为nil的情况(因为当属性值为nil时,NSDictionary会认为初始化结束)。因为在JAVA中有工具通过反射机制可以实现自动的序列化自定义类,于是抱着试一试的心态,开始寻找Objective-C中对应的方法。功夫不负苦心人,一位stackoverflow上的仁兄的回复提醒了我,iOS中的有Runtime Programming这样一种技术,通过阅读相应的文档,最终我找到了解决的方法。

iOS的Runtime Programming中提供了一系列强大的方法在运行时对类进行操作,比如获取类的属性信息,类的协议信息,甚至是修改,增加,删除类的方法。对于我的需求而言,能够获取类的所有属性信息已经足够了。实际上我们需要解决的问题,就是动态的获取一个类中所有的属性名,只要能够获取这个,再通过这些属性名找到对应的属性值,最终把这些名-值建立成对,放入一个NSDictionary中,就可以使用第三方工具完成序列化的工作了。

想到这里,可以说要做什么已经清楚了,接下来就是实干!我用苹果的官方文档给的例子,写了一个获取一个类所有属性名的方法:

?
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
    Foo *foo = [[Foo alloc] init];
     
    id fooClass = objc_getClass("Foo");
     
    unsigned int outCount, i;
     
    objc_property_t *properties = class_copyPropertyList(fooClass, &outCount);  //获取该类的所有属性
     
    for (i = 0; i < outCount; i++)
 
  {
         
        objc_property_t property = properties;
        
 
    //property_getName()返回属性的名字 在Foo中分别是 property1和property2
 
    //property_getAttributes()返回属性的属性,如是retain还是copy之类的
        
 
    //这个方法输出了该类所有的属性名与对应的属性的属性(好绕口啊)
 
    NSLog(@"%s %s\n", property_getName(property), property_getAttributes(property));  
         
    }


我们知道,对于一个定义了@property的NSObject来说,只要调用与属性名相同名字的方法,便可以得到这个属性的值,如:[foo property1];会返回 @"haha" ,为了获取对应属性的值,我们只要把属性的名字用NSSelectorFromString()方法转换成selector,然后让这个类foo来调用就可以了。

至此,可以说所有的难点都解决了,接下来就是把这个些东西组合起来,来生成NSDictionary了。下面的很简单,我就不写了:)
最终序列化的代码如下:

?
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
    NSString *className = NSStringFromClass([theObject class]);
     
    const char *cClassName = [className UTF8String];
     
    id theClass = objc_getClass(cClassName);
     
    unsigned int outCount, i;
     
    objc_property_t *properties = class_copyPropertyList(theClass, &outCount);
     
    NSMutableArray *propertyNames = [[NSMutableArray alloc] initWithCapacity:1];
     
    for (i = 0; i < outCount; i++) {
         
        objc_property_t property = properties;
         
        NSString *propertyNameString = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
         
        [propertyNames addObject:propertyNameString];
         
        [propertyNameString release];
         
        NSLog(@"%s %s\n", property_getName(property), property_getAttributes(property));
         
    }
     
    NSMutableDictionary *finalDict = [[NSMutableDictionary alloc] initWithCapacity:1];
     
    for(NSString *key in propertyNames)
    {
        SEL selector = NSSelectorFromString(key);
        id value = [theObject performSelector:selector];
         
        if (value == nil)
        {
            value = [NSNull null];
        }
         
        [finalDict setObject:value forKey:key];
    }
     
    [propertyNames release];
     
    NSString *retString = [[CJSONSerializer serializer] serializeDictionary:finalDict];
     
    [finalDict release];
     
    return retString;


这里主要是提供一种思路,可能这种解决方法还会有些欠缺的地方,希望可以和大家一起讨论下。内容可能写的有点糙,如果有相关问题,欢迎留言询问。
补充一点,这个方法我不确定能否通过苹果的审核,不过既然苹果的文档让用,我觉得应该没什么问题。
之前排版有点问题,现在好了:)
[ 此帖被freezn在2011-12-13 13:40重新编辑 ]
附件:  JSONAutoSerializer.zip (116 K) 下载次数:358

jQuery序列化表单为JSON对象

姓名: 性别: 男 女 年龄: 20 21 22 ...
  • itmyhome
  • itmyhome
  • 2015年01月04日 21:35
  • 9595

自定义类的实例化对象转JSON--结合Runtime

具体分为两步 第一步将自定义类的实例化对象转为字典,这一步需要结合Runtime进行 第二步使用第一部得到的字典转为JSON数据...
  • ZuoWeiXiaoDuZuoZuo
  • ZuoWeiXiaoDuZuoZuo
  • 2016年05月19日 15:30
  • 841

Java中关于Json对象类型和字符串类型之间互相转化的问题

Json转化的知识例子分享
  • caolipeng_918
  • caolipeng_918
  • 2014年09月13日 16:50
  • 1262

使用Struts 2将Java对象序列化成JSON

Struts 2有个很强大的功能,就是可以自动完成服务器端Java对象和客户端JSON对象之间的映射。这篇文章就介绍一下如何将Java对象序列化成JSON格式并传到客户端。可以看看不同的Java类型和...
  • caokang1314
  • caokang1314
  • 2015年09月09日 13:42
  • 872

alibaba fastjson(json序列化器)序列化部分源码解析- Java综合

本文copy自http://www.flydmeng.com/index.php/code/alibaba-fastjson-json-serializer-chapter-source-analys...
  • Dear_Bee
  • Dear_Bee
  • 2014年02月21日 10:44
  • 1775

【Java】——Json反序列化为Java对象

【项目需求】    最近做项目的时候,功能是将一个表单和一个datagrid中的集合中的数据一起传到后台去,也就是将接送。 【思路】   1、在之前做过的功能中,我们用过@request...
  • u013035538
  • u013035538
  • 2016年07月24日 21:15
  • 4128

javascript jquery将表单form序列化成json提交

终于解决将form表单序列化为json提交的问题,本来很简单,只怪自己当初没看懂~...
  • John_laishaobin
  • John_laishaobin
  • 2015年05月26日 13:04
  • 1467

DataTable序列化为JSON字符串

通常我们使用JavaScriptSerializer或者JSON.NET来序列化一个对象,但对于Datatable来说,其包含的数据比它的可序列化的属性更重要。   我尝试把DataRow转化为一个...
  • qq285679784
  • qq285679784
  • 2017年04月18日 16:34
  • 198

form表单序列化JSON

有时会将前端的数据json化后,传递到后台处理。 在页面提交时,需要将前端form表单中的数据json化,结合form的序列化方法将拥有name的表单域封装成Json结构数据...
  • ThinkingLink
  • ThinkingLink
  • 2015年08月28日 15:01
  • 5260

JSON序列化为java对象

这是一个json对象转换为javabean的具体实例,还可以学到js对象,数组之间的运用。有什么问题,大家多多指教。...
  • tree3170
  • tree3170
  • 2014年06月26日 15:37
  • 617
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:一种自动的将自定义类序列化为JSON的方法
举报原因:
原因补充:

(最多只允许输入30个字)