Skip to content
This repository has been archived by the owner. It is now read-only.

@weakify/@strongify in nested blocks #45

Closed
itsthejb opened this issue Aug 26, 2013 · 17 comments
Closed

@weakify/@strongify in nested blocks #45

itsthejb opened this issue Aug 26, 2013 · 17 comments

Comments

@itsthejb
Copy link

@itsthejb itsthejb commented Aug 26, 2013

Hi,

I have been looking through the library documentation in order to find some guidance on how to use @weakify and @strongify in nested blocks, but cannot find any. For example, which is correct?

1. @weakify once and subsequently @strongify in blocks

- (void) test {
      @weakify(self)
      id block = ^{
        @strongify(self);
        [self doSomething];
        nestedBlock = ^{
          @strongify(self);
          [self doSomethingElse];
        }();
      };
      block();
}

2. Alternate @weakify/@strongify

- (void) test {
      @weakify(self)
      id block = ^{
        @strongify(self);
        [self doSomething];
        @weakify(self)         // @weakify again before the nested block?
        nestedBlock = ^{
          @strongify(self);
          [self doSomethingElse];
        }();
      };
      block();
}

Would be great to get some guidance on what is appropriate here.

Many thanks,

J

@jspahrsummers
Copy link
Owner

@jspahrsummers jspahrsummers commented Aug 26, 2013

It'll make a lot more sense when thinking of @weakify(self) as just a convenient shorthand for __weak id weakSelf = self; and @strongify(self) as shorthand for id self = weakSelf;

Given that, you don't need to create multiple weak variables. Using @weakify just once in a scope is enough.

@itsthejb
Copy link
Author

@itsthejb itsthejb commented Aug 27, 2013

Therefore just once in the parent scope? With no need to @weakify again in any nested scope? Ie. example 1 is correct?

@jspahrsummers
Copy link
Owner

@jspahrsummers jspahrsummers commented Aug 27, 2013

Correct.

@itsthejb
Copy link
Author

@itsthejb itsthejb commented Aug 27, 2013

Great, thanks.

@itsthejb itsthejb closed this Aug 27, 2013
@fabb
Copy link

@fabb fabb commented Mar 19, 2014

Does this mean if I forget the second @strongify, self will be captured strongly again?

- (void) test {
      @weakify(self)
      id block = ^{
        @strongify(self); // shadows self with locally-scoped variable
        [self doSomething];
        nestedBlock = ^{
          //@strongify(self);
          [self doSomethingElse]; // references self shadow from outer block and thus retains self
        }();
      };
      block();
}

@jspahrsummers
Copy link
Owner

@jspahrsummers jspahrsummers commented Mar 19, 2014

@fabb Correct. IME, it's not much of an issue, because the nested blocks typically don't create long-lived cycles (the lifetime is usually finite), but you can add inner @strongify calls to avoid it if it becomes a problem.

@fatuhoku
Copy link

@fatuhoku fatuhoku commented May 5, 2014

How do you determine when a block has finite lifetime vs. when it doesn't? What's the exact scenario in which a retain cycle could be caused by blocks?

@itsthejb
Copy link
Author

@itsthejb itsthejb commented May 5, 2014

@fatuhoku Block retain cycles are just like delegate retain cycles; if self retains a block, which in turn captures self, then you have a retain cycle. Contrast this to, for example, UIView animation blocks which can quite happily reference self but without a cycle because the block is retained by UIKit (not self).

@Ricardo1980
Copy link

@Ricardo1980 Ricardo1980 commented Aug 14, 2014

@itsthejb "Contrast this to, for example, UIView animation blocks which can quite happily reference self but without a cycle because the block is retained by UIKit (not self)." I didn't know that. Where can I read more about that? So i understand when using self inside [UIView animation...{ is not necessary to use weakify or weak, isn't it?

@fabb
Copy link

@fabb fabb commented Aug 14, 2014

@Ricardo1980 I'd rather say it that way: When calling animateWithDuration:animations: with an animations block that contains self, then self will be retained, but after the animation finishes, the animations block will be released, and also self will be released again. So no retain cycle.

@itsthejb
Copy link
Author

@itsthejb itsthejb commented Aug 20, 2014

@Ricardo1980 glad to be of help. I think that example is a good one to make the understanding click - it did for me 😉 As for reading more about it, I'm afraid I don't have any articles I can recommend per se. I think as long as you think about it like a delegate retain cycle (which I hope you understand!) then this all becomes quite clear

@trant
Copy link

@trant trant commented Apr 22, 2015

What about for "parallel" blocks (blocks at the same level of scope)?

[UIView animateWithDuration: kMapButtonsAnimationDuration
                          delay: 0
                        options: UIViewAnimationOptionCurveEaseOut
                     animations:^{
                         @strongify(self) 
                         [self superMan];
                    }
                     completion:^(BOOL finished){
                        [self completionMan];
                     }];

@nemissm
Copy link

@nemissm nemissm commented Mar 29, 2018

@trant, you should write @strongify in completion too.

@k06a
Copy link
Contributor

@k06a k06a commented Mar 29, 2018

And don’t need @strongify In animation block.

@k06a
Copy link
Contributor

@k06a k06a commented Mar 29, 2018

Also aware access class members directly without specifying self this way: self->xxx

@k06a
Copy link
Contributor

@k06a k06a commented Mar 29, 2018

And don’t use super keyword in asynchronous blocks. Wrap calls in separate methods, which will be called by strongified self access.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
8 participants