iOS内存管理--Block属性用copy修饰 & 避免循环引用的问题
Posted zzz098zzz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS内存管理--Block属性用copy修饰 & 避免循环引用的问题相关的知识,希望对你有一定的参考价值。
一、Block的类型
根据Block在内存中的位置分为三种类型NSGlobalBlock,NSStackBlock, NSMallocBlock。
- NSGlobalBlock:类似函数,位于text段;
- NSStackBlock:位于栈内存,函数返回后Block将无效;
- NSMallocBlock:位于堆内存。
不同于NSObjec的copy、retain、release操作:
- Block_copy与copy等效,Block_release与release等效;
- 对Block不管是retain、copy、release都不会改变引用计数retainCount,retainCount始终是1;
- NSGlobalBlock:retain、copy、release操作都无效;
- NSStackBlock:retain、release操作无效,必须注意的是,NSStackBlock在函数返回后,Block内存将被回收。即使retain也没用。容易犯的错误是[[mutableAarry addObject:stackBlock],(补:在arc中不用担心此问题,因为arc中会默认将实例化的block拷贝到堆上)在函数出栈后,从mutableArray中取到的stackBlock已经被回收,变成了野指针。正确的做法是先将stackBlock copy到堆上,然后加入数组:[mutableArray addObject:[[stackBlock copy] autorelease]]。支持copy,copy之后生成新的NSMallocBlock类型对象。
- NSMallocBlock:支持retain、release,虽然retainCount始终是1,但内存管理器中仍然会增加、减少计数。copy之后不会生成新的对象,只是增加了一次引用,类似retain;
- 尽量不要对Block使用retain操作
三、ARC与非ARC下的block
对于引用了外部变量的Block,如果没有对他进行copy
,他的作用域只会在声明他的函数栈内(类型是__NSStackBlock__
),如果想在非ARC下直接返回此类Block,Xcode会提示编译错误的,如下图:
(Xcode提示Returning block that lives on the local stack)
而在ARC环境下,上述代码会编译通过,因为ARC会自动加入copy
操作。
比如可以在ARC下运行如下代码:
//ARC
MyBlock block = func();
NSLog(@"%d", block());
NSLog(@"%@", [block class]);
输出:
123 __NSMallocBlock__
以上是关于iOS内存管理--Block属性用copy修饰 & 避免循环引用的问题的主要内容,如果未能解决你的问题,请参考以下文章
iOS内存管理--NSArray与NSMutableArray用copy修饰还是strong