iOS 正确使用 @weakify(self) 和 @strongify(self)

标签 ios objective-c libextobjc

我开始将 libextobjc (https://github.com/jspahrsummers/libextobjc) 集成到我的 iOS 应用程序中,主要是为了利用 EXTScope 的 @strongify@weakify,但有几个问题在继续深入流程之前。

这是一个故意过于复杂的例子,试图弄清楚如何处理这个问题:

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

    else {
        [[Async HTTPRequest] sendBWithID:self.property.id completionHandler:^{
            // self reference #5
            [self reloadData];
        }];
    }
}

我的理解是,如果我想做异步 HTTP 请求之类的事情,并且在完成处理程序引用 self 内部,例如 [self reloadData],我不需要使用 strong 做任何事情/weak 因为请求 block 本身没有保留完成 block ,所以那里的保留周期没有问题。在上面的代码示例中,我认为 #5 是保留周期不是问题的情况。

主要关注的是所有将 block 作为属性/初始化参数的对象,它们在内部保持 block 属性。在 objectWithCompletionHandler 方法中,其中 someObject 将 completionHandler block 作为实例变量保存,那里有多个对 self 的引用,我知道这会导致泄漏。我的主要问题是在这种情况下,您需要如何处理 weakifystrongify 以使其“更安全”?一个@weakify 和@strongify 调用是否就足够了,如下所示:

- (void)someMethod {
    @weakify (self);

    _someObjectInstanceVar = [Object objectWithCompletionHandler:^{
        @strongify(self);
    ...
}

上面的 @strongify(self) 引用是否足以用于 self 引用 #1、2、3 和 4,还是我必须(并且它甚至可以工作)获得一个在 sendAWithID 方法和嵌套的 reloadData 中使用的新的弱/强引用?

编辑:修复代码以使问题更有意义并修复一些语法错误。

最佳答案

@strongify 的工作原理

@strongify 被调用后,self 将有一个不同的指针地址 inside block 而不是 outside block 。这是因为 @strongify 每次都声明一个名为 self 的新局部变量。 (这就是它抑制 -Wshadow 警告的原因,它会“在局部变量遮蔽另一个局部变量时发出警告。”)值得阅读和理解 the implementation of these functions .因此,即使名称相同,也要将它们视为单独的 strong 引用。

在代码中使用 @strongify

假设(这是不正确的)每次使用 block 都会创建一个引用循环,您可以:

- (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…
}

但是,请记住在您第一次使用 @strongify 之后,self 将引用本地堆栈变量。当定义它们的范围结束时,它们通常会被销毁(只要您不将它们存储到属性或在嵌套 block 中使用它们)。所以根据你展示的代码,你只需要在 //self reference #1 之后。

另见

阅读unit test covering @weakify and @strongify将有助于阐明这些函数的正确用法。

关于iOS 正确使用 @weakify(self) 和 @strongify(self),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28305356/

相关文章:

objective-c - 监控网络流量 Mac

reactive-cocoa - ReactiveCocoa/libextobjc 中的weakify和strongify如何工作的解释

ios - 如果不使用 CoreAnimation 如何避免 "CoreAnimation warning deleted thread with uncommitted CATransaction"

ios - 将 "1900-01-01T00:00:00"字符串值转换为日期

ios - 无法在默认的 iOS 7 日历中创建事件

ios - 苹果开发者成员(member)资格到期

objective-c - Swift 从 .m 文件中读取私有(private)属性

iphone - UIApplication openURL后台