我开始将libexobjc(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做任何事情,因为请求块本身没有保留完成块,所以保留循环没有问题.在上面的代码示例中,我认为#5是一种不存在保留周期问题的情况.

主要关注的是将块作为属性/init参数的所有对象,这些对象在内部保留块属性.在objectWithCompletionHandler方法中,someObject将completionHandler块作为一个实例变量保存,我知道有多个对self-there的引用会导致泄漏.我的主要问题是,在这种情况下,您需要如何处理weakifystrongify以使其"更安全"?一个@weakify和@strongify调用是否足够,如下所示:

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

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

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

编辑:修复了让问题更有意义的代码,并修复了一些语法错误.

推荐答案

How @strongify works

调用@strongify后,self在块中的指针地址inside将与在块中的指针地址outside不同.这是因为@strongify每次都声明一个名为self的新局部变量.(这就是为什么它会 suppress -Wshadow警告,该警告将"在一个局部变量与另一个局部变量相遮挡时发出警告".)它值得阅读和理解.因此,即使名称相同,也要将它们视为单独的strong个参考.

Using @strongify in your code

假设(这不是真的)each use of a block would create a reference cycle,你可以:

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

然而,请记住这一点.当定义它们的范围结束时(只要不将它们存储到属性或在嵌套块中使用它们),它们通常会被销毁.所以根据你展示的代码,你只需要在// self reference #1之后使用它.

另见

阅读unit test covering @weakify and @strongify将有助于澄清这些功能的正确用法.

Objective-c相关问答推荐

Objective C中的简单字符串连接

在从 UIViewController 调用的非保留完成中引用 self 时,weakSelf/strongSelf 舞蹈真的有必要吗?

如何可靠地检测 iOS 9 上是否连接了外部键盘?

如何在 UICollectionView 中居中行?

带有 IB_DESIGNABLE 的 UIButton 会引发运行时属性警告,并且不会在 Interface Builder 中呈现

与 iOS 6.0 原生 Facebook 集成共享:通过我的应用名称发布?

适用于 ios 的 360° 全景库

如何在使用 React Native 时实现 SSL 证书固定

setStatusBarHidden 在 iOS 9.0 中已弃用

如何隐藏/显示导航栏中的右键

dispatch_async(dispatch_get_main_queue(), ^{...});等到完成?

了解按位与运算符

如何将@selector 作为参数传递?

计算 UILabel 文本大小

iOS 11 large-title导航栏不折叠

-[MyClassName copyWithZone:] 无法识别的 Select 器发送到实例

UIView: opaque vs. alpha vs. opacity

iPhone UILabel 文字软阴影

AppDelegate 的当前视图控制器?

performFetchWithCompletionHandler 永远不会被解雇