iOS Proper Use of @weakify(self) and @strongify(self)

后端 未结 3 890
没有蜡笔的小新
没有蜡笔的小新 2021-01-29 21:17

I\'m starting to integrate libextobjc (https://github.com/jspahrsummers/libextobjc) into my iOS application primarily to take advantage of EXTScope\'s @strongify an

相关标签:
3条回答
  • 2021-01-29 21:32

    How @strongify works

    After @strongify is called, self will have a different pointer address inside the block than it will outside the block. That's because @strongify declares a new local variable called self each time. (This is why it suppresses the -Wshadow warning, which will “warn whenever a local variable shadows another local variable.”) It's worth reading and understanding the implementation of these functions. So even though the names are the same, treat them as separate strong references.

    Using @strongify in your code

    Presupposing (which is not true) that each use of a block would create a reference cycle, you could:

    - (void)someMethod {
        if (self.someBOOL) {
            @weakify(self);
            _someObjectInstanceVar = [Object objectWithCompletionHandler:^{
                @strongify(self);
                // self reference #1
                if (self.someProperty) {
                    @weakify(self);
                    // self reference #2
                    [[Async HTTPRequest] sendAWithID:self.property.id completionHandler:^(void (^)(NewObject *newObject) {
                        @strongify(self);
                        // self reference #3
                        @weakify(self);
                        [self showViewWithObject:newObject handler:^{
                            // self reference #4
                            @strongify(self);
                            [self reloadData];
                        }];
                    }];
                }
            }];
        // etc…
    }
    

    However, remember that after your first use of @strongify, self will refer to local, stack variables. These will typically get destroyed when the scope in which they're defined ends (as long as you aren't storing them to properties or using them in a nested block). So based on the code you showed, you only need it after // self reference #1.

    See Also

    Reading the unit test covering @weakify and @strongify will help clarify the correct usage of these functions.

    0 讨论(0)
  • 2021-01-29 21:41

    To answer your question of whether multiple instances of weakify/strongify in each nested level of your blocks works, then yes. But there's no need to do that because, your first @strongify definition already defines self for all of the inner scope of your block (and the blocks that are nested in it).

    However, given that your blocks have different lifetimes, you might want to add @strongify for each nested block to make sure they all hold their own retain cycle to their inner scope.

    Here's the github issue thread that explains this case: https://github.com/jspahrsummers/libextobjc/issues/45

    0 讨论(0)
  • 2021-01-29 21:45

    Calling "self" inside the block that in hold by "self" will lead to "Retain Cycles" and hence memory leaks. So ideally it goes like:

    @interface A: NSObject // Some interface A
    
    @property (nonatomic, copy, readwrite) dispatch_block_t someBlock; // See block is strongly retained here.
    
    @end
    
    *******************************************************
    @implementation A
    
    - (void) someAPI
    {
        __weak A * weakSelf = self; // Assign self to weakSelf and use it
        // enter code here inside block to break retain cycles.
        self.someBlock = 
        ^{
            A * strongSelf = weakSelf; // Assign weak self to strongSelf before
           // using it. This is because weakSelf can go nil anytime and it may happen
           // that only few lines from block get executed before weakSelf goes nil,
           // and hence code may be in some bad state.
            if (strongSelf != nil)
            {
                // Use strongSelf.
                [strongSelf doSomethingAwesome];
                [strongSelf doSomethingAwesomeAgain];
            }
        };
    }
    
    @end
    

    If the block is not retained by "self", then its safe to just use "self" inside blocks and they won't create retain-cycles.

    Note: Memory management concept remains same with use of "libextobjc" library.

    0 讨论(0)
提交回复
热议问题