New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@weakify/@strongify in nested blocks #45

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

Comments

Projects
None yet
8 participants
@itsthejb
Copy link

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

This comment has been minimized.

Copy link
Owner

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

This comment has been minimized.

Copy link
Author

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

This comment has been minimized.

Copy link
Owner

jspahrsummers commented Aug 27, 2013

Correct.

@itsthejb

This comment has been minimized.

Copy link
Author

itsthejb commented Aug 27, 2013

Great, thanks.

@itsthejb itsthejb closed this Aug 27, 2013

@fabb

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Owner

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Author

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Author

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

nemissm commented Mar 29, 2018

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

@k06a

This comment has been minimized.

Copy link
Contributor

k06a commented Mar 29, 2018

And don’t need @strongify In animation block.

@k06a

This comment has been minimized.

Copy link
Contributor

k06a commented Mar 29, 2018

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

@k06a

This comment has been minimized.

Copy link
Contributor

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 join this conversation on GitHub. Already have an account? Sign in to comment