当前位置: 动力学知识库 > 问答 > 编程问答 >

objective c - Understanding weak pointers in block

问题描述:

The following function will not print "nil1" or "nil2" if I call it once.

However, if I put it in a loop, some iterations will print "nil2" ONLY.

What's going on? If user is nil, why "nil1" is not printed?

After remove the __weak directive before the declaration of "weakUser", the function will no longer print "nil" even though it is called multiple times in a loop.

Any ideas of what's going on?

- (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();

}];

}

网友答案:

that is a scheduling issue here, so let us just examine your code from perspective of time. I've added some timestamp marker to your code and let us walk through what really happens at those checkpoints.

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

we can agree in (A) < (B) < (C) < (E) and there are two more scenarios here

  1. (C) < (D) < (E) or
  2. (C) < (E) < (D)

there is no more information about which one of the two scenarios happens with (D).


(A)

you instantiate a __strong User * user in this scope, the end of the scope is at (E) therefore your __strong pointer will keep the instance alive in this context to the end of the scope. you have one retaining reference to your object.

(B)

you make a __weak User * weakUser pointer, that points to a __strong reference what you just established recently at (A). the __weak pointers point to an instance as long as it is kept alive by a __strong reference at least, but they are not retaining references – they become nil immediately when no more __strong reference points to the instance.

(C)

you still have a valid __strong reference to your user and the __weak reference point to the same instance shamelessly, so the instance is still alive and the weakUser is not a nil, therefore the true-branch of if will never run – nothing will be printed ever.

(E)

the scope runs out and the __strong reference to your instance won't be live anymore, therefore it does not keep the user alive after that point. additionally the weakUser immediately becomes nil, because that is not a retaining reference and mo more __strong pointer keeps the user alive.


scenarios for (D):

1. (C) < (D) < (E)

the block runs before the time (E) is reached, the __strong pointer still keeps the instance alive and the weakUser still points to the same instance, therefore the true-branch of if won't perform.

2. (C) < (E) < (D)

the block runs after the time (E) is reached, the __strong pointer is not live anymore, so the instance has been released by now and the weakUser is nil, therefore the true-branch of if performs in this scenario.


NOTE: you can read more about encapsulation and ownership on the Apple's official site.

分享给朋友:
您可能感兴趣的文章:
随机阅读: