前言
过去写iphone程序一直都没有用过自动解析,都是手动按着字典一层一层的解析,这样费时费力,还容易出错。后来公司来了新朋友带来了自动解析的jastor库,着实不错。
简单介绍一下jastor
jastor是一个基于oc运行时的库,它可以将字典对象转换成NSObject对象。它支持NSString, NSNumber,NSArray, NSDictionary以及它们的嵌套类型。例如现在需要将dict转换为model。 dict为NSDictionary对象, model为继承于Jastor的NSObject对象。 Jastor通过遍历model对象的所有属性, 以属性作的名字作为dict的key,得到字典的value值。 然后根据value值的类型,进行不同的处理。 如果value是NSArray类型,那么就进入NSArray的解析流程; 如果value是NSDictionary类型,那么开始进行递归调用,如果是其他普通类型,则直接setvalue:forKey。当进入NSArray的处理流程时候,调用类的“属性_class”方法获取到数组对象的类型,然后对数组对象进行逐步解析,数组对象也必须是字典类型。
为什么写这篇博客?
Jastor确实可以大大简化代码的解析流程,当然效率肯定没有手动解析的效率高,这个可以从代码的递归流程以及使用Runtime的各种遍历方法中可以看出。 但是作为开发人员,这么点的效率损失可以带来大量代码的简洁,减少开发人员的出错几率,它的益处是显而易见的。当第一次使用Jastor时候,着实为它的代码的简洁所吸引,主要的有递归解析思想,rumtime的相关内容, 组合模式,缓存机制。后来加入到代码中后,总会有一些崩溃的情况,主要是一些容错性的问题,毕竟我们没有办法要求服务器下发的json数据每次都是和我们要求的一直,总有一些不一致的情况引起意想不到的问题。
Jastor递归解析
Jastor本身是一个基类,它可以将字典转换成model, 如果字典的某一个成员又是字典,那么它可以递归进去继续解析,直到遇到的是一个普通的单一数据类型例如NSString,NSNumber等等为止,通过这样层层的递归,深入到最里层后也就是Jastor解析的结束。它通过for循环遍历当前类的所有属性,逐一寻找属性在字典里面的value值,根据value值的不同类型以及属性的类型决定下一步进行递归解析还是直接setValueForKey。
if ([dictOrArray isKindOfClass:nsDictionaryClass]) {
value = [dictOrArray valueForKey:jsonKey];
if (value == [NSNull null] || value == nil) {
continue;
}
if ([JastorRuntimeHelper isPropertyReadOnly:[self class] propertyName:classAttrName]) {
continue;
}
// handle dictionary
if ([value isKindOfClass:nsDictionaryClass]) {
Class klass = [JastorRuntimeHelper propertyClassForPropertyName:classAttrName ofClass:[self class]];
if (![klass isSubclassOfClass:[Jastor class]]) {
NSLog(@"服务器返回的数据类型和客户端不一致");
continue;
}
value = [[[klass alloc] initWithDictOrArray:value] autorelease];
}
// handle array
else if ([value isKindOfClass:nsArrayClass]) {
value = [self dealWithArrayValue:value attrName:classAttrName jsonKey:jsonKey];
}
// handle nsnumber
else if([value isKindOfClass:[NSNumber class]]){
value = [(NSNumber *)value stringValue];
}
}
请看上面的代码,当传入的是dict的时候,会进入到此if流程中, 首先判断value是否为空,如果为空,直接跳过;然后判断属性是只读,只读也直接跳过;然后判断value是字典的情况,如果是字典进行递归深入;然后判断是数组的情况,数组进行数组元素的遍历解析,最后判断是NSNumber,得到NSNumber的string值。 得到最后的value后,会进行如下的操作
// handle all others
if (value) {
[self setValue:value forKey:classAttrName];
}
Jastor的Runtime
Runtime用的比较好, 其实里面也就几个方法而已,不过由于用的比较少,可能感觉它有些高大上了,其实仔细看看,也是普通的属性遍历而已。总共就几个方法: 判断属性是否可读,获取一个类对象的所有属性列表数组,判断指定类对象的给定属性的类型。所有的方法基于一个基本的思想: 遍历类对象的所有objc_property_t的属性进行处理。 这里面效率肯定比较低,但是这里面作者用了缓存的思想,无缓冲就遍历并写入缓存,下次直接读缓存。
Jastor的组合模式
派生类的model继承于Jastor,派生类model的某一个属性可能也继承于Jastor。一个大的model是一堆Jastor的子类的组合, 通过这种类似于组合模式的思想,贯穿到递归数据解析中,只是通常的组合模式不是类和属性的组合,而且集合和单品元素的组合,其实原理的精髓是一样的。
Jastor的缓存机制
可以看到里面有各种缓存,包括获取属性列表,是否可读,获取指定属性的类对象,获取常用类的类对象等等,都进行的缓存操作,只用了几个简简单单的字典,却可以大大提高程序的执行效率,相当不错。
Jastor的容错性
Jastor本身已经进行了各种容错,不过对于应用来说还是有些缺陷的,毕竟程序可以出错,但不可以崩溃,这是一个基本准则。因此,我主要通过猜,试验,发现了几个崩溃点,和同事一起进行了修正,加入了几个容错,至少在我们的应用中,并没有出现崩溃的情况。
Jastor的map特性
新版的Jastor加入了map,属性名称可以任意,赋予程序以最大的灵活性。原来我们使用的这一版没有这种内容,我们组的牛人波波同志加入了map机制,刚开始我感觉必要性不是很大,但是随着后期的项目的推进,确实用处极大。
对于Jastor,代码我就不贴了,Github有库,GitHub地址。 对于Jastor出现崩溃的情况,一定要跟进Jastor里面,找到问题,加入保护即可。