22

I understand that you should use @weakify @strongify to avoid retain cycles but I don't completely understand how they actually achieve this?

Jamie Forrest
  • 10,895
  • 6
  • 51
  • 68
nacross
  • 2,013
  • 2
  • 25
  • 37
  • 1
    @jamieforrest I noticed you have edited this question. When I originally asked this question I definitely was referring to ReactiveCocoa in spite of the fact that these macros might originate in libextobjc, in the version I was using they are defined in a header file called RACEXTScope.h this file exists in ReactiveCocoa and is not an external dependency. I think we should maintain ReactiveCocoa in the title with libextobjc appended rather than replacing it. – nacross Oct 27 '14 at 04:19
  • Makes sense. I added it back. – Jamie Forrest Oct 27 '14 at 14:11

3 Answers3

27

code before preprocess:

@weakify(self)
[[self.searchText.rac_textSignal
  map:^id(NSString *text) {
      return [UIColor yellowColor];
  }]
 subscribeNext:^(UIColor *color) {
     @strongify(self)
     self.searchText.backgroundColor = color;
 }];

code after preprocess:

@autoreleasepool {} __attribute__((objc_ownership(weak))) __typeof__(self) self_weak_ = (self);
    [[self.searchText.rac_textSignal
      map:^id(NSString *text) {
          return [UIColor yellowColor];
      }]
     subscribeNext:^(UIColor *color) {
         @try {} @finally {}
 __attribute__((objc_ownership(strong))) __typeof__(self) self = self_weak_; // 1
 self.searchText.backgroundColor = color;  //2
     }];

1: define a new local variable “self”. this will shadow the global one.

2: so here we used the local variable “self”--self_weak_.

tips:

1.if we used self.xxx in block, we should place @strongify(self) over it.

2.don't forget use @weakify(self) to define the variable self_weak_.

(PS: I'm trying to learn English. I hope that you can understand what I'm saying.)

geon
  • 8,128
  • 3
  • 34
  • 41
Hugo
  • 1,122
  • 11
  • 12
  • Correct me if I'm wrong- so, if I forgot to put `@strongify(self)` in the block, then the `self` I use in the block is still the original (not shadowed) self, and will be strongly retained? Still quite error-prone :( – Joseph Lin Apr 30 '14 at 16:57
  • Yes, that sounds about right. We need a a new Obj-C syntax with strongify / weakify built in! – fatuhoku May 05 '14 at 11:28
19

When writing the question I stared harder at the macro definitions and I think it works as you might guess.

@weakify creates a new weakly referenced variable of the same type you pass in and assigns the original value to it

@strongify creates a variable that matches the original variable but it exists in the local scope and assigns to it the variable created by @weakify

nacross
  • 2,013
  • 2
  • 25
  • 37
0

First and foremost, it matters what implementation of @weakify & @strongify you're using as these aren't part of the standard language. Assuming you're using the ReactiveCocoa version, here's a nice article about what they are and how they work.

Here are a few relevant quotes:

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

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.

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

user3099609
  • 2,318
  • 18
  • 20
  • My original question was about reactive cocoa. The inclusion of libextobjc was as result of an edit by other users who felt this question applied to that case as well, I cannot say if it does or does not. – nacross Jan 02 '16 at 03:44