Mantle的一个坑被我踩到了,快来围观

来源:互联网 发布:wifi免费打电话软件 编辑:程序博客网 时间:2024/05/20 06:55

   最近用到了一个Mantle这个库的一个功能点,就是通过获取MTLModel的hash值,来唯一区分不同的model对象。(这些model可能属于同一个类,也可能不属于同一个类),印象中MTLModel对hash方法进行了重写,就是为了实现这个目的,我兴冲冲的开始要使用了,但是为了保险起见,我这边进行了相关的单元测试,发现这个方法还是有一些问题的。

MTLModel中的hash方法实现如下:

- (NSUInteger)hash {    NSUInteger value = 0;    for (NSString *key in self.class.propertyKeys) {        value ^= [[self valueForKey:key] hash];    }    return value;}

可以看出主要是对属性值取hash值操作,然后进行相应的异或操作。
为了测试方便,我这边使用了kiwi的测试框架
新建了一个类JKModel

#import <Mantle/Mantle.h>@interface JKModel : MTLModel@property (nonatomic,copy) NSString *name;@property (nonatomic,copy) NSString *home;@end

测试代码如下:
这里写图片描述

大家可以看到单元测试没有通过,说明这两种情况下并不能通过hash值来作为model的唯一标识。通过对MTLModel的源码分析,我们发现重写的hash方法并没有对key进行相关的处理,没有体现出key,value的一一对应关系,只要是两个model的有相关的值,哪怕是key没有对应,依然会判断为model的hash值相等。为了解决这个问题,我新写了一个类对hash方法进行适当的改造。

- (NSUInteger)hash {    NSUInteger value = 0;    for (NSString *key in [[self class] getProperties]) {        value ^= [[NSString stringWithFormat:@"%@&&%lu",key,[[self valueForKey:key] hash]] hash];    }    return value;}+ (NSArray *)getProperties {    //用于存入属性数量    unsigned int outCount = 0;    //获取属性数组    objc_property_t *propertyList = class_copyPropertyList([self class], &outCount);    NSMutableArray *arrM = [NSMutableArray arrayWithCapacity:outCount];    //遍历数组    for (int i = 0; i < outCount; ++i) {        objc_property_t property = propertyList[i];        //获取属性名        const  char *cName = property_getName(property);        //将其转换成c字符串        NSString *propertyName = [NSString stringWithCString:cName encoding:NSUTF8StringEncoding];        //        加入数组        [arrM addObject:propertyName];    }    //在使用了c函数的creat, copy等函数是记得手动释放,要不然会引起内存泄露问题    free(propertyList);    return arrM.copy;}

然后我们重新进行测试,看看效果如何。

SPEC_BEGIN(TDModelSpec)describe(@"TDModel", ^{    context(@"测试BaseModel hash方法", ^{        it(@"如果两个model对象情形1", ^{            TDModel *model1 = [TDModel new];            model1.name =@"张三";            model1.home = nil;            TDModel *model2 = [TDModel new];            model2.name =nil;            model2.home = @"张三";            [[theValue([model1 hash]) shouldNot]  equal:theValue([model2 hash])];        });        it(@"如果两个model对象情形2", ^{            TDModel *model1 = [TDModel new];            model1.name =@"张三";            model1.home = @"111";            TDModel *model2 = [TDModel new];            model2.name =@"111";            model2.home = @"张三";            [[theValue([model1 hash]) shouldNot]  equal:theValue([model2 hash])];        });    });});SPEC_END

测试结果通过。
大家如果在使用到这个点的时候需要注意一下哦。
demo如下:http://download.csdn.net/download/hhl110120/9941950
注:没打算要积分的,现在必须要设置积分了,大家如果没有积分的话,可以私信我

如果有哪里考虑的不正确,或者不完善的欢迎大家批评指正,一块交流进步。

原创粉丝点击