最近用到了一个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
注:没打算要积分的,现在必须要设置积分了,大家如果没有积分的话,可以私信我
如果有哪里考虑的不正确,或者不完善的欢迎大家批评指正,一块交流进步。