as the question described, will the wSelf in block become dangling?
1 void bindDefaultCallbacks {
2 __weak typeof(self) wSelf = self;
2 [sessionManager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) {
4 __strong typeof(self) sSelf = wSelf;
5 if (!sSelf) {
6 return;
7 }
8
9 // will wSelf here become dangling ?
10 APIRequest *apiRequest = [wSelf apiRequestForTask:dataTask];
11 NSURLResponse *response = dataTask.response;
12 apiRequest.urlResponse = response;
13 }];
14 }
crash info:
Exception Codes: SEGV_ACCERR at 0x0000000000000010
Exception Type: SIGSEGV
0 XXX ___73-[XXXX bindDefaultCallbacks:withSessionManager:]_block_invoke.251 (in XXX) 420
1 XXX -[AFURLSessionManager URLSession:dataTask:didReceiveData:] (in XXX) (AFURLSessionManager.m:1156) 20
At line 10, you will not have a dangling pointer. ARC will ensure that the pointer is valid or nil (Chris's reference explains this). However, it is possible that at line 10, the pointer will be nil. There is no promise that the
sSelfreference will continue after line 5 since it is not used after that.There is also no promise that that
wSelfwill be nil at line 10. Either situation is valid. It is only promised that it is either a valid pointer toselfor nil.The formal definition of this rule comes from the Clang documentation discussion of Precise Lifetime Semantics (emphasis added):
See the surrounding section on "Object liveness" for more explanation.
While it would be very difficult for this particular code to fail (the object would need to be deallocated on a different thread during a very brief window between line 5 and line 10), this general situation is actually a fairly common cause of bugs. In debug builds, strong references tend to live until the end of their scope, but in optimized builds, they tend to be released as quickly as possible. So code that works fine during development can fail (or even crash if you're using raw pointers into objects you believe are being retained) when shipped.
This bug was so common that there are annotations in UIKit to help prevent it. If you look at UIColor.h, you'll see the
CGColorproperty defined this way:The
NS_RETURNS_INNER_POINTERis a warning to ARC that this pointer should cause the object's lifetime to be extended even though normally ARC wouldn't require it. (This was an obnoxious and common cause of crashes in the early days of ARC.)