如果我调用一次,以下功能将不会打印“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();
}];
}
答案 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),这里还有两个场景
(D)没有更多关于这两种情况中哪一种情况的信息。
您在此范围内实例化__strong User * user
,范围的结尾位于(E)因此,您的__strong
指针将使实例在此上下文中保持活动状态范围的结束。你有一个保留对象的引用。
你制作一个__weak User * weakUser
指针,指向最近在(A)建立的__strong
引用。 __weak
指针指向一个实例,只要它至少由__strong
引用保持活动,但它们不保留引用 - 当不再有nil
时它们立即成为__strong
引用指向实例。
您仍然对__strong
和user
引用的有效__weak
引用无耻地指向同一个实例,因此该实例仍处于活动状态且weakUser
为不是nil
,因此if
的真分支永远不会运行 - 永远不会打印任何内容。
范围用完了,对您的实例的__strong
引用将不再存在,因此在此之后它不会使user
保持活动状态。此外,weakUser
会立即变为nil
,因为这不是保留引用,并且更多__strong
指针会使user
保持活动状态。
块运行,__strong
指针仍然保持实例处于活动状态且weakUser
仍然指向对于同一个实例,因此if
的真分支将不会执行。
在到达(E)之后,块运行,__strong
指针不再存在,因此该实例现已被释放, weakUser
为nil
,因此if
的真分支在此方案中执行。
注意:您可以在Apple's official site上阅读有关封装和所有权的更多信息。