ivar memory layout
设置ivar 修饰符
@implementation XFADModel {
NSString *_ad_id;
// non exist __copy
__strong NSString *_ad_id_y;
__weak NSString *_ad_id_x;
__unsafe_unretained NSString *_ad_id_xshd;
}
获取ivar修饰符:
class_getIvarLayout
, class_getWeakIvarLayout
引用下这个文章:iOS学习之Objective-C Class Ivar Layout的使用
若储存 strong ivar 的 ivarLayout 的值为 0x012000
储存 weak ivar 的 weakIvarLayout 的值为 0x1200
一个 uint8_t 在 16 进制下是两位,所以编码的值每两位一对儿,以上面的 ivarLayout 为
例:
前两位 01 表示有 0 个非 strong 对象和 1 个 strong 对象 之后两位 20 表示有 2 个非 strong 对象和 0 个 strong 对象 最后两位 00 为结束符,就像 cstring 的 \0 一样 同理,上面的 weakIvarLayout:
前两位 12 表示有 1 个非 weak 对象和接下来连续 2 个 weak 对象 00 结束符
这样,用两个 layout 编码值就可以排查出一个 ivar 是属于 strong 还是 weak 的,若都没 有找到,就说明这个对象是 unsafe_unretained.
那么 通过动态创建的ivar 默认的属性是啥呢?
无论是 ivarLayout
, weakIvarLayout
其结果反馈指针的值都是0x00,那么默认属性是__unsafe_unretained
吗?
看看以下代码:
- (void)setHumanNameValue:(id)aHumanObject {
NSMutableString *fitch = [[NSMutableString alloc]initWithString:@"fitch"];
[aHumanObject setValue:fitch forKey:@kHuMan_name];
[fitch appendFormat:@" Li"];
}
以上函数返回后,如果是__unsafe_unretained
属性, 那么在函数返回后, fitch指针会被释放,此时访问再访问kHuMan_name属性,会crash掉,而事实并没有,这说明动态创建ivar,默认属性为 __strong
, 那么对于数值类的是怎么处理的呢?
class_addIvar(MyClass, kHuMan_age , sizeof(int), log2(sizeof(int)), @encode(int));
考虑使用一下代码:
- (void)setHumanAge:(id)aHumanObject {
NSNumber *aNumber = @13;
NSString *poc = [NSString stringWithFormat:@"%p", &aNumber];
NSLog(@"%@", poc);
[aHumanObject setValue:aNumber forKey:@kHuMan_age];
}
id human_age = [aHumanObject valueForKey:@kHuMan_age];
##################
// human_age = 13
和上面原理一样,当函数退出时,NSNumber会被释放,这里使用log打印指针自身地址,
当,当函数返回时,再查看一下该地址的值,发现值被刷新了,足以说明不是strong,而是assign 其实也可以理解,一个数值类型的怎么strong呢?(不经过malloc出来的数值类型直接存在栈里面,栈退出了,你还指向那个位置有什么用呢?)如果能strong那以什么样的方式用来存储额外的strong信息的。
当NSNumber 存储BOOL 类型的时候,那就是对象了,现在换个Bool 型的,看看是怎么存储的
class_addIvar(MyClass, kHuman_isYoung , sizeof(BOOL), log2(sizeof(BOOL)), @encode(BOOL));
- (void)setHumanIsYoung:(id)aHumanObject {
NSNumber *aNumber = @YES;
NSString *poc = [NSString stringWithFormat:@"%p", aNumber];
NSLog(@"setHumanIsYoung addres: %@", poc);
[aHumanObject setValue:aNumber forKey:@kHuman_isYoung];
}
id human_isYoung = [aHumanObject valueForKey:@kHuman_isYoung];
这里可以看到 ,这下NSNumber是一个对象
总结
对于动态创建的ivar,如果是对象的话 则采用strong
引用方式, 是数值则是assign
, 但是 使用动态创建的话,ivarLayout
和 weakIvarLayout
的返回值不会刷新, 当然你可以手动设置layout
,但是还是不要这么做了,很危险啊,在没有彻底弄明白class内存布局的情况下,贸然使用set layout可能导致非预期的结果