5

In Objective-C, what does it mean to assign a weak to a strong within a block? What's happening behind the scene?

e.g.

__weak __typeof(self) wself = self;

void (^cmd)() = ^(){
    __strong __typeof(self) sself = wself;
    if (!sself) return;
    ...
};
Boon
  • 40,656
  • 60
  • 209
  • 315
  • am not pretty sure about this but i think assigning weak to strong is a logic to add a reference to the object, because weak does not keep the referenced object alive and when there are repetitions it makes a new reference... – Saad Chaudhry Dec 16 '13 at 17:26
  • 2
    I had some really complex networking code that used both strong and weak self, and I wrote a blog about it that may make it clearer: https://dhoerl.wordpress.com/2013/04/23/i-finally-figured-out-weakself-and-strongself/ – David H Dec 16 '13 at 17:28
  • @DavidH good one Boon also have a look at http://stackoverflow.com/questions/11013587/differences-between-strong-and-weak-in-objective-c – Saad Chaudhry Dec 16 '13 at 17:37

2 Answers2

10

The intent here is two-fold:

  1. First, is the use of:

    __weak __typeof(self) wself = self;
    

    This ensures that the cmd block does not maintain a strong reference to self. This ensures that, if cmd was an instance variable of the class, that you don't end up with a strong reference cycle. If you don't use this wself pattern, the class that has cmd as an instance variable would never be released and you'd leak the object that has cmd as an instance variable.

    For more information, see the Avoid Strong Reference Cycles when Capturing self section of the Programming with Objective-C: Working With Blocks document.

  2. Second, the use of the following within the block:

    __strong __typeof(self) sself = wself;
    if (!sself) return;
    

    This ensures that, if the block starts execution, if wself was already deallocated, the block would quit. But if wself has not yet been deallocated, by assigning sself, you're making sure that the object will be retained during the execution of the block.

    Also, if you reference any ivars in the block, be aware that you want to dereference them (because otherwise there is an implicit reference to self in the block, potentially leading to that strong reference cycle). But you cannot dereference ivars using a weak pointer (e.g. wself->someIvar is not permitted), but you can with this local strong pointer (e.g. sself->someIvar is ok). Generally you shouldn't be dereferencing ivars anyway, but rather use properties, but nonetheless it's another reason to use a local strong reference to self.

Often, you'll see this construct in conjunction with a class property (or an ivar):

@property (nonatomic, copy) void (^commandBlock)(void);

And, as a matter of convention, you'll generally see more descriptive variable names, weakSelf and strongSelf, thus:

__weak __typeof(self) weakSelf = self;

self.commandBlock = ^(){
    __strong __typeof(self) strongSelf = weakSelf;
    if (!strongSelf) return;
    ...
};

This weakSelf/strongSelf pattern is very common when you have your own block properties to your class and you want to (a) prevent strong reference cycles (aka retain cycles); but (b) want to ensure that the object in question cannot be deallocated in the middle of the execution of the block.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Like the chunking of knowledge. Thank you. – Boon Dec 16 '13 at 19:00
  • "by assigning sself, you're making sure that the object will be retained during the execution of the block." I struggle to see how deallocation can realistically happen. The block is called, either through the `self` object, or not. 1) If it is not called through `self`, something else must have a (strong) reference to the block (or something that retains the block). So the block (or something that owns it) is first stored as an instance variable in `self`, then given to something else to retain before `self` dies. I would argue this is not very common, and can be easily checked by the user. – newacct Dec 18 '13 at 09:40
  • 2) If it is called through the `self` object (through some pointer to the `self` object), then this is analogous to calling a method on the `self` object. This is because, in methods in ARC, `self` is not retained. So whatever situation can cause deallocation in the middle of that block that is called through the object somehow, can also analogously happen in the middle of a method called through the object, in the same way. Apparently the ARC guys decided that this was so unusual that they didn't bother to retain `self`. – newacct Dec 18 '13 at 09:41
  • @Rob: I did not assume how the block is run. I'm saying that if the network operation runs in the background and is retained by that background process, it would usually not need to be retained by the view controller. Also, anything that updates the UI should be run on the main thread, so this problem should not occur. – newacct Dec 18 '13 at 18:43
  • @newacct You misunderstand me. But perhaps it doesn't matter: If your point is that the race condition is unlikely, that's true (but all race conditions are inherently unlikely). If your point is that it never happens, then we'll agree to disagree. But see Apple's discussion of "non-trivial cycles" at the end of the [ARC Introduces New Lifetime Qualifiers](https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW4) section of the _Transitioning to ARC RN._ – Rob Dec 18 '13 at 19:20
5

If you don't assign weak reference to a strong the object referenced by the weak reference can be deallocated in the middle of the block execution - something you might not expect. if you assign to strong the object is retained for as long as the strong reference is in scope (unless the object has already been deallocated prior to the assignment).

When you assign a weak reference to a strong compiler inserts Objective-C runtime function call into the code that increments the object reference counter as needed to retain it. When the strong variable goes out of scope (or earlier, after the last use of the strong variable) another call inserted by compiler decrements the reference counter.

yurish
  • 1,515
  • 1
  • 15
  • 16
  • What's happening behind the scene? Does the assignment to strong causes the ref count to go up? – Boon Dec 16 '13 at 18:06
  • I do not know all the details of the ARC machinery (it may perform some optimizations) but conceptually you can think that when you assign the reference to strong variable the reference counter is incremented. – yurish Dec 16 '13 at 18:10
  • @Boon While we're not supposed to be thinking in terms of "retain counts" any more, yes, the assignment to local strong variable within the block will result in the retain count to be incremented when the block executes (but not before) and the retain count will be reduced when the block completes execution and the `sself` variable falls out of scope. – Rob Dec 18 '13 at 12:13