Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
260 views
in Technique[技术] by (71.8m points)

ios - Is the weakSelf/strongSelf dance really necessary when referencing self inside a non-retained completion called from a UIViewController?

Say I have the following method inside a UIViewController subclass:

- (void)makeAsyncNetworkCall
{
    [self.networkService performAsyncNetworkCallWithCompletion:^{
        dispatch_async(dispatch_get_main_queue(), ^{
                [self.activityIndicatorView stopAnimating];
            }
        });
    }];
}

I know that the reference to self inside the block results in the UIViewController instance being retained by the block. As long as performAsyncNetworkCallWithCompletion does not store the block in a property (or ivar) on my NetworkService, am I right in thinking there is no retain cycle?

I realise this structure above will lead to the UIViewController being retained until performAsyncNetworkCallWithCompletion finishes, even if it is released by the system earlier. But is it likely (or even possible?) the system will deallocate my UIViewController at all (after the changes to the way iOS 6 manages a UIViewController's backing CALayer memory)?

If there is a reason I must do the "weakSelf/strongSelf dance", it would look like this:

- (void)makeAsyncNetworkCall
{
    __weak typeof(self) weakSelf = self;
    [self.networkService performAsyncNetworkCallWithCompletion:^{
        typeof(weakSelf) strongSelf = weakSelf;
        if (!strongSelf) {
            return;
        }
        dispatch_async(dispatch_get_main_queue(), ^{
                [strongSelf.activityIndicatorView stopAnimating];
            }
        });
    }];
}

But I find this unconscionably ugly and would like to avoid it if it's not necessary.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As I believe you correctly diagnosed, using self will not necessarily cause strong reference cycle in this scenario. But this will retain the view controller while the network operation completes, and in this case (as in most cases), there's no need to. Thus, it may not be necessary to do use weakSelf, but probably prudent to do so. It minimizes the chance of an accidental strong reference cycle and leads to more efficient use of memory (releasing the memory associated with the view controller as soon as that view controller is dismissed rather than unnecessarily retaining the view controller until after the network operation is complete).

There is no need for the strongSelf construct, though. You can:

- (void)makeAsyncNetworkCall
{
    __weak typeof(self) weakSelf = self;
    [self.networkService performAsyncNetworkCallWithCompletion:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakSelf.activityIndicatorView stopAnimating];
        });
    }];
}

You only need the weakSelf/strongSelf combination where it's critical to have a strong reference (e.g., you're dereferencing ivars) or if you need to worry about race conditions. That does not appear to be the case here.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...