Look at the document from Apple:
When a block is copied, it creates strong references to object variables used within the block. If you use a block
within the implementation of a method:
●If you access an instance variable by reference, a strong reference is made to self;
●If you access an instance variable by value, a strong reference is made to the variable.
The following examples illustrate the two different situations:
dispatch_async(queue, ^{
// instanceVariable is used by reference, a strong reference is made to self
doSomethingWithObject(instanceVariable);
});
id localVariable = instanceVariable;
dispatch_async(queue, ^{
/*
localVariable is used by value, a strong reference is made to localVariable
(and not to self).
Blocks and Variables
Object and Block Variables
*/
doSomethingWithObject(localVariable);
});
To override this behavior for a particular object variable, you can mark it with the __block storage type
modifier.
使用方法总结如下:(只对应NON-ARC的情况)
- 如果block没有被copy,则block中的变量在stack空间中被创建。一旦此scope执行完毕,此stack空间被释放。
- 如果block被copy,则block中的所有变量被拷贝到heap中。
此时,可以看作所有的变量都被重新拷贝了一份。
1. 对于 int, float等基本类型的变量,不需要担心release的问题,但是赋值操作将不会影响到stack空间中的变量(即block scope外的原变量)。
2. 对于objective c对象,如果直接调用self中变量,则self会被retain。由于在self中copy了这个block,会造成循环引用。
解决方法是:声明__block blockSelf = self, 在block中调用blockSelf的变量。
(注意:TestClass *blockSelf = self, blockSelf和self都指向同一个内存地址,当self先于blockSelf被释放时,blockSelf就变成了野指针!!
真的是这样吗?实际测试过,如果加上了__block,self不会先释放,会等到block执行完之后才释放。) - 如果是
id localVariable = instanceVariable;
把localVariable传进block,则localVariable会被retain。
例子:
@ property (nonatomic, copy) RequestCompleteBlock copiedCompleteBlock;
@ property (nonatomic, copy) RequestFailureBlock failure;
TestClass *testObject = [TestClass node];
self.copiedCompleteBlock = ^(NSData *data) {
[self performSelector:@selector(execute:data:) withObject:testObject afterDelay:3.0f];
};
self.failure = ^(NSError *error){
testObject.name = @"wang";
};
// set request type, HTML
FWURLRequest *defaultRequest = [FWURLRequest defaultRequest];
defaultRequest.requestType = FWE_REQUESTTYPE_HTML;
[defaultRequest requestWithURL:url
paramsDicData:params
completeBlock:self.copiedCompleteBlock
failBlock:self.failure];
因为在copiedCompleteBlock和failure中testObject都被retain了,但是这两个block只有一个会被调用到,所以无论如何testObject都不会被释放。
3. 如果声明了__block的objective c对象,可以理解成,此对象的指针地址被拷贝到了heap(其指针实际指向的地址并没有被拷贝),它指向实际地址空间的retain count并没有增加,所以读写都有效。也不需要进行额外的release。
注意,如上例子,如果
__block TestClass *testObject = [TestClass node];
因为testObject不会被retain,当程序运行到当前scope外时,此testObject会被release,如果在此之后copiedCompleteBlock才被调用,则程序会崩溃。
建议:
1. 对于非self的object,不要使用__block,因为在block释放时会自动释放这些object。
2. 对于self的object,
1. 对于非self的object,不要使用__block,因为在block释放时会自动释放这些object。
2. 对于self的object,
You have a few options. 1) When not using ARC, the __block qualifier on an object pointer causes it to be non-retained. Thus: __block Whatever *weakSelf = self; ^{ [weakSelf ...]; } 2) When using ARC on 10.7/iOS5, the __weak qualifier gets the same job done, but even better. __weak qualified variables are zeroing, so they're safer to use. 3) If you're using ARC but have to support 10.6/iOS4, the __unsafe_unretained qualifier will give you a non-zeroing weak pointer. 4) My MAZeroingWeakRef library provides functionality similar to __weak, but works without ARC and on older OSes. For example: MAZeroingWeakRef *weakSelfRef = [MAZeroingWeakRef refWithTarget: self]; ^{ [[weakSelfRef target] ...]; } Since this is a zeroing weak reference, it's safer to use than __block or __unsafe_unretained. You can get it here with a liberal license: https://github.com/mikeash/MAZeroingWeakRef