理解块中的弱指针

时间:2014-07-22 08:24:01

标签: objective-c pointers callback objective-c-blocks weak-references

如果我调用一次,以下功能将不会打印“nil1”或“nil2”。 但是,如果我把它放在一个循环中,一些迭代将打印“nil2” ONLY

这是怎么回事?如果用户为零,为什么不打印“nil1”?

在声明“weakUser”之前删除__weak指令后,即使在循环中多次调用该函数,该函数也不再打印“nil”。

有关正在发生的事情的任何想法?

- (void)hello: (void(^))callback
{
    User *user = [[User alloc] init]; // user is not nil 

    __weak User *weakUser = user; // removing __weak won't cause problems.
    if(weakUser == nil)
    {
        NSLog(@"nil1");
    }
    [ABC func: ^{
        if(weakUser == nil)
        {
            NSLog(@"nil2");
        }
        callback();
    }];
}

1 个答案:

答案 0 :(得分:1)

这是一个调度问题,所以让我们从 time 的角度来检查你的代码。我已经为你的代码添加了一些时间戳标记,让我们来看看那些检查点真正发生的事情。

- (void)hello: (void(^))callback {
    // TIMESTAMP(A)
    User *user = [[User alloc] init]; // user is NOT nil 

    // TIMESTAMP(B)
    __weak User *weakUser = user;

    // TIMESTAMP(C)
    if(weakUser == nil) {
        NSLog(@"nil1");
    }

    [ABC func: ^{
        // TIMESTAMP(D)
        if(weakUser == nil) {
            NSLog(@"nil2");
        }
        callback();
    }];

// TIMESTAMP(E)
}

我们可以同意(A)< (B)< (C)< (E),这里还有两个场景

  1. (C)< (D)< (E)
  2. (C)< (E)< (d)
  3. (D)没有更多关于这两种情况中哪一种情况的信息。


    (A)

    您在此范围内实例化__strong User * user,范围的结尾位于(E)因此,您的__strong指针将使实例在此上下文中保持活动状态范围的结束。你有一个保留对象的引用。

    (B)

    你制作一个__weak User * weakUser指针,指向最近在(A)建立的__strong引用。 __weak指针指向一个实例,只要它至少由__strong引用保持活动,但它们不保留引用 - 当不再有nil时它们立即成为__strong引用指向实例。

    (C)

    您仍然对__stronguser引用的有效__weak引用无耻地指向同一个实例,因此该实例仍处于活动状态且weakUser为不是nil,因此if的真分支永远不会运行 - 永远不会打印任何内容。

    (E)

    范围用完了,对您的实例的__strong引用将不再存在,因此在此之后它不会使user保持活动状态。此外,weakUser会立即变为nil,因为这不是保留引用,并且更多__strong指针会使user保持活动状态。


    (D)

    的情景

    1。 (C)< (D)< (E)

    在到达(E)之前,

    块运行__strong指针仍然保持实例处于活动状态且weakUser仍然指向对于同一个实例,因此if的真分支将不会执行。

    2。 (C)< (E)< (d)

    到达(E)之后,块运行__strong指针不再存在,因此该实例现已被释放, weakUsernil,因此if的真分支在此方案中执行。


    注意:您可以在Apple's official site上阅读有关封装和所有权的更多信息。