3

I discover this snippet code from company's document:

__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{
      __strong __typeof(weakSelf)strongSelf = weakSelf; 
      // Do stuff
});

It's will be retained ?

Quang Dam
  • 305
  • 3
  • 15
  • That is the correct way to avoid a retain cycle using blocks. The strong reference is to a weak referece so you avoid the retain cycle. I usually use `__strong typeof(self)strongSelf = weakSelf;` since `self` is the same in both cases. – Dennis W. Jun 16 '16 at 04:10
  • But, I think the weak reference outside block is enough. It's right? – Quang Dam Jun 16 '16 at 04:16
  • yes, you are right or simply make reference outside block as `__weak CLASSNAME *weakSelf = self;` and use weakSelf variable inside block. – Sunil Sharma Jun 16 '16 at 06:18
  • Apple's block programming guide show only using weakself, however, in the 2012 WWDC video Asynchronous Design Patterns with Blocks, GCD, and XPC they use strongself as a means to check if self is nil before executing the code in the block. – Dennis W. Jun 16 '16 at 15:34

3 Answers3

8

There are two reasons to capture weak references within a block.

  1. avoid retain cycles

  2. create no-op situations.

The former has been discussed ad-nauseum. The second is more interesting.

Example

The block in question is a completion handler for an image download. When the download is complete, it is to be displayed in an image view.

It doesn't need to do anything if the image view has already been deallocated (say the user has switched to a new view). There is no danger of a retain cycle, because the image view has no reference to the block. However, capturing a weak reference allows the image view to be deallocated before the block executes. Thus, if the user switches views before the image is downloaded, the block ends up doing nothing because its weak reference has already been niled. It also doesn't matter if the image view is deallocated part way through the block's execution, because it just turns operations on the image view into no-ops, instead of turning the entire block into a no-op.

Sometimes, however, the block wants the no-op behavior, but only if the reference was already nil when it began (or reached a certain point in the code path). If, at the time the block executes, the object is live, the block has to execute in its entirety. It can't stop half-way through because the object is deallocated on some other thread.

Example

The purpose of the completion block is to add a caption, defined by a string, to the image. If the string has been deallocated already, no caption is to be added. However, if the string is still live when post-processing begins, it must remain live to avoid trying to create an attributed string with a nil reference, because that leads to a crash.

In this scenario, it would be proper to capture the string with a weak reference, so it can be deallocated by some other thread (leading to no caption). However, before the string is used within the block, it must be captured strongly to avoid a crash when creating the attributed string.

Avi
  • 7,469
  • 2
  • 21
  • 22
  • thanks for this good writeup, but I can't tell from just the English exactly what you're saying. Can you add code that matches the narrative? Moreover, both of these examples seem to me straight-forwardly code-able without adding any funny strong-qualified refs to unretained stack variables. – danh Jun 16 '16 at 17:11
  • 2
    Hey - this was bugging me, so I asked a friend who works for Apple on iOS. The short answer is, you're right. We use the weakSelf to avoid a cycle, and the strong copy to prevent deallocation during execution of the block. The checklist for when we'd want this approach is pretty obscure, though: (a) the retain cycle with the block (rare), (b) multithreaded use of self where it is released with uncertainty (rare), (c) code in the block that mentions the self pointer more than once, (d) use of the self pointer where having nil-ed is harmful (very rare). a*b*c*d = RARE. (continued...) – danh Jun 16 '16 at 22:37
  • 1
    Rare, but you're correct. It's that last (d) condition you were struggling to exemplify here, and I don't think you quite succeeded. Nevertheless, thanks for learnin' me something new. +1, here. I'll leave my own answer up since its not wrong. I'm tempted to delete my wrong comments, but maybe I'll just add a last one, in case others find useful my ignorance followed by newfound understanding. – danh Jun 16 '16 at 22:39
1

The weak copy outside the block is enough.

__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{
      // silliness: __strong __typeof(weakSelf)strongSelf = weakSelf; 
      // Do stuff with weakSelf here
});

In fact, this is okay too:

dispatch_async(dispatch_get_main_queue(),
^{
    // self self self, go ahead and mention self here
});

The thing one must not do is copy that block someplace, and mention that someplace in the block.

@property (nonatomic, strong) void (^myBlock)(void);

self.myBlock = ^void(void) {
    // don't mention self here!
};

The idea is that blocks retain the objects they mention, and we're trying to avoid cycles, so object -> block -> another_object is fine, but object -> block -> another_object -> any amount of indirection -> object is a cycle, and that's bad.

Cycles are bad because an object can't be deallocated if it's retained elsewhere, and so the things it retains can't be deallocated. If two things retain each other, then they're both stuck, unable to be deallocated because each is retained by something.

EDIT what I misunderstood until today is that the strong copy of the weak var isn't always silly. It can be relevant, but the case where it makes sense is highly qualified).

danh
  • 62,181
  • 10
  • 95
  • 136
  • This is a way I always use. But why they use Strong Self? – Quang Dam Jun 16 '16 at 04:53
  • I've seen it a few times too, and its the result of someone not understanding copying the code of someone else who doesn't understand. – danh Jun 16 '16 at 04:57
  • 2
    There is a reason to use a strong version of a weak reference within a block. It's not the result of a misunderstanding, though it may be over-used by those who don't understand. Creating a strong reference within the block ensures that the object so referenced will remain live during the execution of the block. Without this assurance, the object could be deallocated part-way through. Sometimes this is OK, sometimes it's not. – Avi Jun 16 '16 at 05:06
  • @danh the whole point of `weakSelf` is block don't retain it. so `strongSelf` is required to convert weak reference to strong reference – Bryan Chen Jun 16 '16 at 05:09
  • 1
    @BryanChen - Yes, and that's needed when that weakSelf or something it retains retains the block. If that cycle isn't present, then the weakSelf isn't necessary. And the "strong" declaration inside the block is superfluous. If you want it strong, don't declare it weak to begin with. – danh Jun 16 '16 at 05:13
  • The `strongSelf` include block is needed if `weakSelf` is used. In this question, `weakSelf` doesn't make sense so there is no need to have `strongSelf`. But in most of the other cases where retain cycle need to be broken, `weakSelf` and `strongSelf` are needed to ensure `self` don't get released halfway through the block. – Bryan Chen Jun 16 '16 at 05:19
  • @danh, you are missing the point. You may have a block that should do nothing if it executes after some object has already been deallocated. For this, you capture a weak reference. You may simultaneously desire that if the block is to start performing its work, that this work complete before the object is deallocated. For this, you need a strong reference. It is precisely this scenario for which the strong->weak->strong conversion is necessary and desired. It's not a mistake or bad design. – Avi Jun 16 '16 at 05:19
  • @Avi - I guess I am missing the point. Is there a reference somewhere that explains what you're trying to explain to me? – danh Jun 16 '16 at 05:25
  • I don't know of one. It's just plain common sense applied to ARC. Unfortunately, this comment mechanism is horrible for explaining, because I can't even get paragraphs, never mind real formatting. – Avi Jun 16 '16 at 05:35
  • @Avi - Agreed. Maybe write up an answer here that's better than mine, walking through a scenario where the strong copy of the weak copy is needed. "Two objects walk into a bar..." that sort of thing. I'll be happy to learn something new, if not a little surprised. – danh Jun 16 '16 at 05:39
  • Please see @Avi's answer and my comment below. There is a case for the strong copy of the weak pointer, albeit obscure. (A retain cycle with the block PLUS a potential release of the object in a multithreaded app PLUS potential harm due to use of the nil-ed reference.) – danh Jun 16 '16 at 22:43
1

If you use this:

__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(),
^{ 
    // Do stuff
});

Self may get deallocated while the block is being executed. So we had better to convert the weakSelf to strongSelf to ensure that self stays in memory until the block finishes execution.

After your use of __strong __typeof(weakSelf)strongSelf = weakSelf, self will refer to local, stack variables. So It's will not be retained.

Tony
  • 542
  • 3
  • 13