-(void) performOperation { void(^completionBlock) (id obj,NSError *err,NSURLRequest *request)= ^(id obj,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,NSURLRequest *request)
在:
__block void(^completionBlock) (id obj,NSURLRequest *request)
但我得到这个其他警告:
WARNING 2: Capturing 'completionBlock' strongly in this block is likely to lead to a retain cycle
如何解决这个问题?
谢谢
尼古拉
解决方法
WARNING: Block pointer variable ‘completionBlock’ is uninitialized
when captured by the block
这是因为初始化为递归块的块变量需要__block存储.
>复制一个块内的变量,除非用__block声明,在这种情况下它们作为参考传递.
>将递归块分配给块变量时,创建发生在分配之前,并且此类创建触发变量副本.鉴于变量尚未分配,复制的变量将是一个错误的值,并且将在块运行时产生崩溃.
>但是,如果我们添加__block,则将使用对该变量的引用来创建该块.然后变量将被初始化为创建的块,块将可以使用.
WARNING: Capturing ‘completionBlock’ strongly in this block is likely
to lead to a retain cycle
这是因为块变量是对块的强引用,并且块本身引用变量(因为如前所述,变量具有__block,因此被引用而不是复制).
所以我们需要
>一个弱参考块内的强变量.
>而且还有一个强有力的参考,以防止在创建块的方法中释放块.
void(^ completionBlock) (id obj,NSURLRequest *request); void(^ __block __weak weakCompletionBlock) (id obj,NSURLRequest *request); weakCompletionBlock = completionBlock = ^(id obj,NSURLRequest *request){ [self lengthyAsyncMethod:weakCompletionBlock]; };
名称doLengthyAsynchronousOperationWithCompletionBlock表明该方法可能会超过创建块的方法范围.鉴于编译器不会复制作为参数传递的块,因此该方法有责任复制此块.如果我们正在使用具有块感知代码的块(例如:dispatch_async()),则会自动发生.
如果我们将这个块分配给一个实例变量,我们需要一个@property(copy)和一个对块内部的self的弱引用,但事实并非如此,所以我们只是使用self.