Search code examples
objective-cobjective-c-blocksselfweak-references

Idiom to hide `self` in Objective C blocks?


When I have an Objective C instance create a block that needs to refer to the instance, I frequently do so through a weak pointer that won't keep the instance alive and produce a retain cycle, like this:

__weak MyType *const weakSelf = self;
void (^aBlock)() = ^(){
  // Do things with weakSelf instead of self.
}

I'd like to have an idiom that prevents me from making use of the strong self in the block. Ideally, when using the idiom, I'd get a compile error if I try to use self in the block instead of weakSelf. A run time error would also be okay.


Solution

  • I've got a solution for this that I don't especially like, but it might provoke a better answer. I'll leave this unanswered in the hope of a better solution arriving.

    Here's one way to do it:

    // Here's a method definition…
    -(void) aMethod
    {
      // Want to create a block in which its impossible to refer to strong "self".
      // Begin a new scope to do this in.
      {
        // Within this scope, cover the existing "self" with a weak variant.
        __weak STWeatherTableViewController const *weakSelf = self;
        __weak STWeatherTableViewController const *self = weakSelf;
    
        // Sadly it's _not_ possible to simply do:
        //   __weak STWeatherTableViewController const *self = self;
        // … it gives a warning about initialisation of a variable form its own
        // uninitialised value, which makes sense, though you might hope the
        // compiler would work out what's going on.
    
        // Make a block that captures the covered self and does something with it.
        void (^exampleBlock)() = ^(){ [self lineHeight]; };
        exampleBlock();
      }
    
      // Now, back in the scope of the original method, "self" is non weak
      // again.
      [self doSomething];
    }
    

    I guess, if you really cared a lot about this, you could use a macro. It would at least abstract the idea and make uses easy to find and notice in code:

    #define WEAKEN_SELF(classType) \
    __weak classType const *weakSelf = self; \
    __weak classType const *self = weakSelf
    

    Or even:

    #define WEAKEN_SELF(classType) \
    __weak classType const *weakSelfTemporary##__LINE__ = self; __weak classType const *self = weakSelfTemporary##__LINE__;
    

    Which you'd use it like this:

    -(void) testMethod
    {
      // You still need that scope or you cover the original "self".
      {
        WEAKEN_SELF(STWeatherTableViewController)
        void (^exampleBlock)() = ^(){ [self someMethodOrOther]; };
        exampleBlock();
      }
    }
    

    I'm unconvinced it is worth the effort though. Having the compiler warnings is probably good enough and they can presumably be turned in to errors?