iOS下的__block与__weak
来源:互联网 发布:javascript转义字符 编辑:程序博客网 时间:2024/05/18 21:08
先看下结论:
所有对象在编译之后,都会转换成一个结构体,包括block,和被__block修饰的任意变量,形成一个拷贝(你可以用clang 将oc转c即可验证)。被__block修饰的变量,转换后的结构体里包含一个_forwarding指针,指向自己的拷贝(从栈到堆的拷贝)。因此:
__block id weakS=[MyViewController new]; //假设这里的指针weakS变量本身的地址(不是指向地址)A int i= [weakS retainCount]; self.block=^{ int j = [weakS retainCount]; NSLog(@"doing blk %@",weakS); }; //假设这里weakS的本身地址B, int k= [weakS retainCount];
上述代码里的地址A和地址B是不相等的,你可以自己去打印下。
而__weak,在转换之后却是一条gc指令(自动垃圾回收)。
很多人在arc下用__block来避免循环引用,其实是无效的,依然会导致内存泄露,可以自己新建一个类来在dealloc方法里进行信息打印,看是否 执行。
如果你一定要在arc下用__block,尽量避免循环,如果无法避免下,你依然要用,也有一个办法,就是在block最后一行,将对象设置为nil
__block id weakS=[MyViewController new]; self.block=^{ /*某些个其他代码*/ NSLog(@"doing blk %@",weakS); weakS = nil ; };
如上,但是以上办法有一个缺陷,便是,如果你的block未被执行,就肯定会有泄露,因为weakS =nil,最终并未被执行。
修饰语WordA Tsobj * tobj =self; NSObject * obj2 =[[NSObject alloc] init]; _obj.aBlk =^{ NSObject *obj =[[NSObject alloc] init]; /*场景1*/ tobj->_name = obj.description; /*场景2*/ _name = obj.description; /*场景3*/ tobj.name = obj.description; };
针对不同修饰语,不同场景,会是怎么样的呢?如表:
为什么场景2在所有场景下都会内存泄露呢?我们看下此时block转化成IMP后的代码,如下:
static void __Tsobj__heh_block_func_0(struct __Tsobj__heh_block_impl_0 *__cself) { /*请重点看下面这行A*/ Tsobj *self = __cself->self; // bound by copy Tsobj *tobj = __cself->tobj; // bound by copy NSObject *obj2 = __cself->obj2; // bound by copy NSObject *obj =((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init")); /*和重点看下面这行B*/ (*(NSString **)((char *)self + OBJC_IVAR_$_Tsobj$_name)) = ((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)obj, sel_registerName("description"));// (*(NSString **)((char *)tobj + OBJC_IVAR_$_Tsobj$_name)) = ((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)obj2, sel_registerName("description")); }
看一下上面重点注释的那两行,block转化IMP后带了一个指针,这个指针有一个 ->self,也就是self对象被retain了,然后在有注释的代码B行里,通过self指针,来访问成员变量。而不是直接通过成员变量的指针。
换句话说,如果block里直接访问成员变量,此时ratain的是self,而不是直接retain成员变量。
我们在看看被__weak修饰的block变量会如何:
static void __Tsobj__heh_block_func_0(struct __Tsobj__heh_block_impl_0 *__cself) { /*看这里*/ Tsobj *__weak tobj = __cself->tobj; // bound by copy NSObject *obj =((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init")); ((void (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)tobj, sel_registerName("setName:"), ((NSString *(*)(id, SEL))(void *)objc_msgSend)((id)obj, sel_registerName("description"))); }static void _I_Tsobj_heh(Tsobj * self, SEL _cmd) { (*(Tsobj **)((char *)self + OBJC_IVAR_$_Tsobj$_obj)) =((Tsobj *(*)(id, SEL))(void *)objc_msgSend)((id)((Tsobj *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Tsobj"), sel_registerName("alloc")), sel_registerName("init")); /*看这里*/ __attribute__((objc_gc(weak))) Tsobj * tobj =self; ((void (*)(id, SEL, void (*)()))(void *)objc_msgSend)((id)(*(Tsobj **)((char *)self + OBJC_IVAR_$_Tsobj$_obj)), sel_registerName("setABlk:"), ((void (*)())&__Tsobj__heh_block_impl_0((void *)__Tsobj__heh_block_func_0, &__Tsobj__heh_block_desc_0_DATA, tobj, 570425344)));}
我们可以看到,系统添加了attribute((objc_gc(weak))) 修饰对象。
- iOS下的__block与__weak
- ios __block与__weak
- iOS中的__block 与__weak
- iOS __block 与 __weak区别
- __weak与__block的区别
- iOS学习笔记29-__block 与 __weak的区别理解
- [iOS]__weak与__block修饰符的区别
- iOS开发之 __block 与 __weak的区别理解
- iOS __block和__weak的区别
- __block 与 __weak的区别与使用
- iOS - __weak&&__block
- __block 与 __weak的区别理解
- __block 与 __weak的区别理解
- __block与__weak的区别理解
- __weak与__block修饰符的区别
- __block 与 __weak的区别理解
- __block 与 __weak的区别理解
- __block 与 __weak的区别理解
- LeetCode--Happy Number
- Android_获取系统状态栏高度
- Apache Commons-SCXML系列之项目介绍
- 一个简单的端口扫描程序
- Linux---gdb调试
- iOS下的__block与__weak
- 循环链表
- Erlang OTP源码分析 – gen_server
- 《读书笔记》系列1:UNIX环境高级编程
- iOS微信支付
- Groovy中的Actor模型_网页设计
- Liferay学习之一:环境搭建
- 黑马程序员_java基础_面向对象
- xcode7 真机测试