如何解决在这个区块强烈的“捕捉”区块可能会导致一个保留周期“

我正在处理这个代码,它在网上做了一些冗长的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。