如何修复"捕获“块”强烈该块很可能导致保留周期" [英] How to fix "Capturing 'block' strongly in this block is likely to lead to a retain cycle"

查看:155
本文介绍了如何修复"捕获“块”强烈该块很可能导致保留周期"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的这个code,它确实在网络上的一些冗长的asyncronous操作,当它完成它触发其中执行一些测试一结束块,如果一个变量得到一定值的另一冗长的操作应立即启动

   - (无效)performOperation
{    无效(^ completionBlock)(ID OBJ,NSError *呃,*的NSURLRequest要求)= ^(ID OBJ,NSError *呃,*的NSURLRequest要求){
        int变量= 0;        //完成完成操作的
        // ...
        // ...        //完成完成操作B
        //获取变量值        如果(变量大于0){
            [个体经营doLengthyAsynchronousOperationWithCompletionBlock:completionBlock];
        }    };//上述completionBlock执行lenhgty操作
    [个体经营doLengthyAsynchronousOperationWithCompletionBlock:completionBlock];} - (无效)doLengthyAsynchronousOperationWithCompletionBlock:completionBlock
{
    //做一些冗长的异步的东西
}

有了这个code我从编译器这样的警告:

 警告:当块caputerd块指针变量completionBlock未初始化

我改了:

 无效(^ completionBlock)(ID OBJ,NSError *呃,*的NSURLRequest要求)= ^(ID OBJ,NSError *呃,*的NSURLRequest要求)

  __块无效(^ completionBlock)(ID OBJ,NSError *呃,*的NSURLRequest要求)= ^(ID OBJ,NSError *呃,*的NSURLRequest要求)

但我得到这等警示:

 警告2:捕获completionBlock强烈该块很可能导致保留周期

我该如何解决这个问题?

感谢

尼古拉


解决方案

  

警告:块的指针变量'completionBlock未初始化
  当块捕获


这是因为初始化递归块需要 __块存储。

块变量

  • 块中的变量被复制,除非与宣布__块,在这种情况下,他们是作为引用传递。

  • 当递归块被分配给一个块变量,创立了分配之前发生,并且这样的创建触发变量副本。鉴于变量尚未分配,复制的变量将是一个坏的价值,当块运行它会产生一个崩溃。

  • 但是,如果我们添加 __块,该块将被用为变量,而不是一个参考创建。则变量将被初始化为所创建的块,以及该块将准备使用。


  

警告:捕获completionBlock强烈该块可能
  导致一挡周期


这是因为一个块变量是一个强大的参考块,块本身是引用变量(因为正如我们之前所看到的,变量有一个 __块因此它被引用,而不是复制)。

因此​​,我们需要


  • 的弱引用块内的强变量。

  • 和外面的强引用prevent从它创建的方法的范围时被释放块。


    无效(^ completionBlock)(ID OBJ,NSError *呃,*的NSURLRequest要求);
    无效(^ __block __weak weakCompletionBlock)(ID OBJ,NSError *呃,*的NSURLRequest要求);
    weakCompletionBlock = completionBlock = ^(ID OBJ,NSError *呃,*的NSURLRequest要求){
        [个体经营lengthyAsyncMethod:weakCompletionBlock];
    };

名称 doLengthyAsynchronousOperationWithCompletionBlock 显示,该方法可以活得比在其中创建块的方法范围。由于编译器不会复制作为参数传递块,它的这种方法复制此块的责任。如果我们使用的块意识到code此块。(如: dispatch_async()),这是自动发生

如果我们被这个块分配给一个实例变量,我们需要一个 @property(复印件)和弱参考块中的自我,但是这​​不是如此,因此我们只需使用自我。

I am working on this code, which does some lengthy asyncronous operation on the net and when it finishes it triggers a completion block where some test is executed and if a variable get a certain value another lengthy operation should start immediately:

-(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
}

With this code I get this warning from the compiler:

WARNING: Block pointer variable 'completionBlock' is uninitialized when caputerd by the block

I changed:

void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request)

in:

__block void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request)

but I get this other warning:

WARNING 2: Capturing 'completionBlock' strongly in this block is likely to lead to a retain cycle

How can I fix this?

Thanks

Nicola

解决方案

WARNING: Block pointer variable 'completionBlock' is uninitialized when captured by the block

This happens because block variables initialized to a recursive block need __block storage.

  • Variables within a block are copied unless declared with __block, in which case they are passed as reference.
  • When a recursive block is assigned to a block variable, the creation happens before the assignment, and such creation triggers a variable copy. Given that the variable hasn't been assigned yet, the copied variable will be a bad value, and it will produce a crash when the block is ran.
  • But if we add __block, the block will be created with a reference to the variable instead. Then the variable will be initialized to the created block, and the block will be ready to use.

WARNING: Capturing 'completionBlock' strongly in this block is likely to lead to a retain cycle

This happens because a block variable is a strong reference to the block, and the block is itself referencing the variable (because as we saw before, the variable has a __block so it is referenced instead copied).

So we need

  • A weak reference to the strong variable inside the block.
  • And a strong reference outside to prevent the block from being deallocated during the scope of the method where it is created.

    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];
    };

The name doLengthyAsynchronousOperationWithCompletionBlock suggests that the method may outlive the method scope where the block is created. Given that the compiler doesn't copy a block passed as an argument, it's responsibility of this method to copy this block. If we are using this block with block aware code (eg: dispatch_async()), this happens automatically.

Had we been assigning this block to an instance variable, we would need a @property(copy) and a weak reference to self inside the block, but this is not the case, so we just use self.

这篇关于如何修复"捕获“块”强烈该块很可能导致保留周期"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆