Why you should start using @weakify and @strongify macros

I have to admit something. I haven't used @weakify and @strongify macros in any of my projects yet. A recent discussion in my team at Macoscope and a discussion on Twitter started by Peter Steinberger sparked my interest in these macros. Read on to learn what I found out and why I think they're the way to go in most scenarios.

Standard approach of breaking retain cycles

Let's say we have a view controller with a property called model. We want to have a label's text update when the data inside the model changes. To do that we set up a model:

- (void)setUpModel
{
  Model *model = [Model new];

  // this block is called by the model when its underlying data changes
  model.dataChanged = ^(NSString *title) {
    self.label.text = title;
  };

  self.model = model;
}

With these few innocent lines of code we introduced a retain cycle. Our view controller retains the model, which in turn retains a block holding the view controller. We can easily break this retain cycle, by introducing new local variables with __weak and __strong1 storage type modifiers:

Model *model = [Model new];

__weak typeof(self) weakSelf = self;
model.dataChanged = ^(NSString *title) {
  __strong typeof(self) strongSelf = weakSelf;
  strongSelf.label.text = title;
};

self.model = model;

This so called weak/strong dance can be found in most Objective-C codebases. It works fine, but it's error prone. When the new features are introduced and the block's definition gets bigger someone will eventually use self within it. We won't notice when it happens — the compiler helps only in the most simple cases. This is a part when weakify and strongify macros come in handy.

weakify and strongify

Original implementation of @weakify and @strongify macros is complex because they accept more than one parameter. To make the analysis simpler, we'll introduce our own versions, accepting only one parameter each:


#define weakify(var) __weak typeof(var) AHKWeak_##var = var;

#define strongify(var) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
__strong typeof(var) var = AHKWeak_##var; \
_Pragma("clang diagnostic pop")

With these macros in-place, our example takes the following form:


Model *model = [Model new];

weakify(self);
model.dataChanged = ^(NSString *title) {
  strongify(self);
  self.label.text = title;
};

self.model = model;

which—with pragmas omitted—translates to:

Model *model = [Model new];

__weak typeof(self) AHKWeak_self = self;
model.dataChanged = ^(NSString *title) {
  __strong typeof(self) self = AHKWeak_self;
  self.label.text = title;
};

self.model = model;

In the block, self is overshadowed by a local variable with the same name. Then, self can be used safely inside the block, because it references that local variable, which is held strongly, but lives only until the block ends executing. Even the code not written by us can use self safely, e.g. NSAssert macro.

It's still possible to reference the real self, by using an ivar. It leads to a warning, though, so it's a mistake that's easy to spot:

Block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior

Now, you may ask: what if I forget to use strongify? This is a cool part: weakify creates a new local variable, so if it's not used at all we get a warning:

Unused variable 'AHKWeak_self'

This warning won't help us, if a strongified self is used in more than one block. This can be worked around by introducing a new scope for each block definition, e.g.:

{
  weakify(self);
  model.dataChanged = ^(NSString *title) {
    strongify(self);
    self.label.text = title;
  };
}

{
  weakify(self);
  model.syncFinished = ^(BOOL success) {
    strongify(self);
    [self update];
  };
}

It's not pretty, and I would hesitate before doing things this way, but I think it can be useful in some cases.

As you can imagine, if you forget to use weakify, but strongify is in its place, the compiler shows an error:

Use of undeclared identifier 'AHKWeak_self'

Final thoughts

To sum up: we still have to think about a possibility of retaining self (or some other object) when creating a new block. That's not something any macro can help us with. However, once weakify and strongify macros are used, any future changes to blocks' definitions are safer than with the standard weak/strong dance.

As for Swift, a similar construct called capture list is embedded into the language itself.


  1. Technically, in this case we don't need strongSelf — we could just use weakSelf instead. However, when there's more than one use of self inside the block, we generally don't want it to get niled out during the block's execution.