【问题标题】:Understanding weak pointers in block理解块中的弱指针
【发布时间】:2014-07-22 08:24:00
【问题描述】:

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

这是怎么回事?如果用户为 nil,为什么不打印“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();
    }];
}

【问题讨论】:

  • 为什么要打印"nil1"weakUser 根本不是nil,你只是用一个强指针在同一范围内实例化了一个对象,user 指向上面的一行..."nil1" 将是在这种情况下从未打印过。
  • "nil2" 仅在您的块运行之前释放user 时打印。当您的方法完成时,您可以指望user 将立即成为nil,但是没有关于 when 块在此上下文中完全运行的信息,也就是 after 你的方法已经完成或之前
  • 如果您从weakUser 中删除__weak,则该指针将自动变为__strong,并且您的块通过weakUser 使对象保持活动状态,直到该块被释放。
  • @holex 在“hello”调用超出范围时用户被释放后可能会执行块上的好点。谢谢。

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


【解决方案1】:

这是一个调度问题,所以让我们从时间的角度检查您的代码。我在您的代码中添加了一些时间戳标记,让我们了解一下这些检查点的实际情况。

- (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) 中达成一致,这里还有两个场景

  1. (C) 或
  2. (C)

没有更多信息说明 (D) 会发生两种情况中的哪一种。


(A)

你在这个作用域中实例化了一个__strong User * user,作用域的结束是在(E),因此你的__strong指针会在这个上下文中保持实例存活到作用域的结束.你有一个对你的对象的保留引用。

(B)

您创建了一个__weak User * weakUser 指针,该指针指向您最近在(A) 建立的__strong 引用。 __weak 指针指向一个实例,只要它至少通过 __strong 引用保持活动状态,但它们不会保留引用 - 当不再有 __strong 引用指向实例时,它们会立即变为 nil

(C)

你仍然有一个有效的__strong 引用到你的user 并且__weak 引用无耻地指向同一个实例,所以该实例仍然存在并且weakUser 不是nil,因此if 的真正分支将永远运行 - 永远不会打印任何内容。

(E)

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


(D)的场景:

1。 (C)

块运行时间(E)到达之前,__strong 指针仍然保持实例活动,weakUser 仍然指向同一个实例,因此if 的真分支不会执行。

2。 (C)

块运行时间达到(E)时,__strong 指针不再存在,所以现在实例已经被释放,@ 987654347@ 是nil,因此if 的真分支在这种情况下执行。


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

【讨论】:

    猜你喜欢
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-11
    • 2013-03-07
    • 1970-01-01
    • 1970-01-01
    • 2015-06-26
    相关资源
    最近更新 更多