Search code examples
iosobjective-c-blocksretain

Block retain on iOS


Could someone help me understand which approach is 'best' with regard to avoiding a block retain cycle..

__weak typeof(self) weakSelf = self;
weakSelf.myProperty = @"something";

vs

self->myProperty = @"something";

The later is being recommended by xCode 5.1 and the former is what seems to be historically recommended.

Thanks


Solution

  • The only time Apple really talks about self->_ivar syntax is when they're observing out that a reference to some instance variable, _ivar, alone, is really equivalent to self->_ivar, and thus referring to _ivar within a block will implicitly retain self. But they're not really recommending you use self->_ivar, just pointing out the issue associated with using instance variables within blocks, that they entail implicit references to self.

    You said:

    A 'Semantic Issue' warning generated by Xcode. The issue is described as "Block implicitly retains self". The 'fix-it' pop generated by Xcode suggests 'Insert self->'

    I can only guess that the suggestion by Xcode is to ensure that implicit references to self are replaced with explicit references, and thus, when you employ the weakSelf pattern, you'll be able to see each reference to self that needs replacing. Clearly, it would be hard for Xcode to know the name of your __weak rendition of self, so it's hard for it to suggest that, but their proposed edit does help avoid missing some implicit reference to self.

    By the way, once you convert those ivar references, e.g. _ivar, with self->_ivar, it will be tempting to then simply go through the code in the block, replacing the references to self with your new weakSelf variable. But be careful: The construct weakSelf->_ivar is problematic because if weakSelf is nil, that will generate a EXC_BAD_ACCESS at runtime. If this ivar is simply backing some property, then use the property (e.g. weakSelf.property). Property accessor methods correctly handle nil pointers (doing nothing), but dereferencing an ivar of a nil pointer will generate the EXC_BAD_ACCESS.

    Ideally in that scenario, just use the property accessor method instead and you're done. But, if there is no property associated with this _ivar, then you have to employ the pattern joking referred to as the "weakSelf/strongSelf dance". So, let's assume you had code that looked like:

    someBlockVariable = ^{
        // do something
    
        // now try to set an ivar
    
        _ivar = ...;
    };
    

    Doing that _ivar to self->_ivar change that Xcode suggests, and then substituting weakSelf, you'd end up with:

    typeof(self) __weak weakSelf = self;
    
    someBlockVariable = ^{
        // do something
    
        // now try to set an ivar
    
        weakSelf->_ivar = ...;
    };
    

    But that's bad (for the reasons I describe above). In fact, the compiler will even warn you that you cannot dereference a weak pointer. So what you'd want to do is:

    typeof(self) __weak weakSelf = self;
    
    someBlockVariable = ^{
        // do something
    
        // now try to set an ivar
    
        typeof(self) strongSelf = weakSelf;
    
        if (strongSelf) {
            strongSelf->_ivar = ...;
        }
    };
    

    And don't worry about the reference to typeof(self) in the block, as that will not retain self.