如何解决在这个区块强烈的“捕捉”区块可能会导致一个保留周期“
我正在处理这个代码,它在网上做了一些冗长的asynchronous操作,当它完成时,它会触发一个完成块,在那里执行一些testing,如果一个variables获得了一个特定的值,另一个冗长的操作应该立即开始:
-(void) performOperation { void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request){ int variable=0; // Do completion operation A //... //... // Do completion operation B //Get the variable value if(variable>0){ [self doLengthyAsynchronousOperationWithCompletionBlock: completionBlock]; } }; //Perform the lenhgty operation with the above completionBlock [self doLengthyAsynchronousOperationWithCompletionBlock: completionBlock]; } -(void) doLengthyAsynchronousOperationWithCompletionBlock: completionBlock { //Do some lengthy asynchronous stuff }
有了这个代码,我从编译器得到这个警告:
WARNING: Block pointer variable 'completionBlock' is uninitialized when caputerd by the block
我变了:
void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request)
在:
__block void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request)
但是我得到了另一个警告:
WARNING 2: Capturing 'completionBlock' strongly in this block is likely to lead to a retain cycle
我怎样才能解决这个问题?
谢谢
尼古拉
警告:块被指针variables“completionBlock”未被初始化
发生这种情况是因为块variables初始化为recursion块需要__block
存储。
- 除非用
__block
声明,否则复制块中的variables,在这种情况下,它们作为参考传递。 - 当recursion块被分配给块variables时,创build发生在赋值之前,并且这样的创build触发variables拷贝。 假定variables尚未分配,复制的variables将是一个不合适的值,并且在块运行时会产生崩溃。
- 但是,如果我们添加
__block
,那么将会使用对该variables的引用来创build块。 然后variables将被初始化为创build的块,并且该块将准备好使用。
警告:在此块中强烈捕获'completionBlock'可能会导致保留周期
发生这种情况的原因是块variables是对块的强引用,块本身引用variables(因为我们之前看到,variables有一个__block
所以它被引用而不是复制)。
所以我们需要
- 对块内强variables的弱引用。
- 另外还有一个强大的引用来防止块在创build方法的范围内被释放。
void(^ completionBlock)(id obj,NSError * err,NSURLRequest * request); void(^ __block __weak weakCompletionBlock)(id obj,NSError * err,NSURLRequest * request); weakCompletionBlock = completionBlock = ^(id obj,NSError * err,NSURLRequest * request){ [self lengthyAsyncMethod:weakCompletionBlock]; };
名称doLengthyAsynchronousOperationWithCompletionBlock
表明该方法可能会超出创build块的方法范围。 假定编译器不复制作为parameter passing的块,则此方法的职责是复制此块。 如果我们使用块感知代码(例如: dispatch_async()
)使用此块,则会自动发生。
如果我们把这个块分配给一个实例variables,我们需要一个@property(copy)
和一个对块内部自我的弱引用,但事实并非如此,所以我们只使用self。