我有一个复杂的发布,我需要展示和取消多个视图控制器.我有一段代码,其中我需要在表示中使用延迟;我想知道在下面这dispatch_after个块的代码中,我使用strongSelf/weakSelf是否合适,或者我是否应该对代码进行改进.我知道这是过时的Objective-C,我正在使用一个旧的、大型的代码库.

__weak typeof(self) weakSelf = self;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{//CURRENT
    
    __strong typeof(self) strongSelf = weakSelf;
    
    [strongSelf presentViewController:strongSelf.coverVC animated:NO completion:^{
        
        [strongSelf showWindowWithImage:NO];
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            
            __strong typeof(self) strongSelf2 = weakSelf;

            [strongSelf2 dismissViewControllerAnimated:YES completion:^{

                strongSelf2.coverVC = nil;
                [strongSelf2 hideWindow];
            }];
        });
    }];
});

推荐答案

这段代码有点奇怪,可能是由不完全了解weakSelf模式的用途的人编写的,更不用说更复杂的weakSelf/strongSelf模式了.诚然,这些可能会让新程序员望而却步,当Objective-C程序员第一次遇到块和强引用周期时,他们经常开始在代码中到处散布弱引用.这看起来像是可疑的.

因此,让我们后退一步:我们在两种情况之一中使用weakSelf模式:

  1. dispatch_after在0.1秒内触发之前,self(视图控制器)可能被解除;或者

  2. 使用非弱self可能会导致一个强劲的参考周期.

在这种情况下,第一种情况似乎非常不可能(但我们需要更多地了解用户界面才是积极的),而第二种情况似乎根本不适用,因为这里没有明显的强烈参考周期风险.

撇开这一点不谈,让我们讨论一些场景,在这些场景中,您将进一步复杂化weakSelf模式,其中包含额外的strongSelf(在本例中是两个).在以下两种情况下,我们都会这样做:

  1. 我们需要在空值会导致错误的某些上下文中使用"弱self "引用;或者

  2. 你想保护自己不受竞争条件的影响,在竞争条件下,你正在执行步骤A和B,而"self"可能会在这段时间内变为空,但重要的是,如果你执行了步骤A,那么你也执行了步骤B.

同样,我不确定这两种情况中的任何一种是否适用于这里.感觉原来的程序员似乎是条件反射地在他们的异步模式中插入了weakSelf/strongSelf模式,可能不知道它是否真正需要.


底线是,在处理大型遗留代码库时,我不确定我是否会在这个特定的代码片段上浪费任何时间.

在我看来,weakSelf的整个用法看起来完全没有必要,但是在您删除所有这些weakSelfstrongSelfstrongSelf2引用之前,您需要确保:(a)没有强烈的引用周期风险(我在你在这里与我们分享的代码中没有看到);以及(b)不存在视图控制器可能从此处未示出的某个其它机制解除的情形.

不过,我想知道上述问题能否简化为以下几点:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self presentViewController:self.coverVC animated:NO completion:^{
        [self showWindowWithImage:NO];
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self dismissViewControllerAnimated:YES completion:^{
                self.coverVC = nil;
                [self hideWindow];
            }];
        });
    }];
});

简而言之,仅仅因为您使用了完成处理程序块,并不意味着您必须使用weakSelf模式.我们通常只在存在实际较强的参考周期风险时才这么做.我在这里看不到任何这样的风险.

但是,如果你考虑这种变化,你真的需要测试它,以确保你没有引入任何新的强引用循环(即,使用"调试存储器图"调试器特征)和/或设想其中视图控制器被过早地解除的某些替代流.我不确定所有这些开发开销仅仅是为了消除这三行代码是否有必要.所有这一切都是假设您在准备示例时没有简化代码,隐藏了一些其他微妙的强引用周期风险,而这些风险在您的问题中没有显示出来.

在处理遗留代码库时,您必须权衡更改的好处和与更改相关的开发/测试开销.就我个人而言,虽然代码对我来说"过于复杂",但我可能会问,这是否是验证更改的最佳资源使用方式.

Ios相关问答推荐

SwiftUI拖动手势和内容拖动时的奇怪行为( skip /卡顿)

SwiftUI绑定到特定的一个或多个枚举 case

Flutter 翼项目.升级到XCode 15.0.1`pod install`抛出错误FlutterMacOS.podspec.json 3.13.2的ParserError

IOS-获取本地化系统映像

使用标头UICollectionViewFlowLayout时的简单SwiftUI视图错误

iphone 11 和 iphone 12 对于相同的布局显示不同的结果

Strange UIView.animate更改UIButton标题 colored颜色 的行为

将 URLCache 子类与 URLSession 一起使用

视觉扫描无法识别 iOS16 上的 GS1 条码特殊字符

如何在Collection 后更改并保留按钮 colored颜色 ,然后在 SwiftUI 中切换回来?

swiftUI中的剪辑形状无法使用旋转效果

有哪些可靠的机制可以防止 CoreData CloudKit 中的数据重复?

如何使用 Swift 文档注释

UICollectionView 添加 UICollectionCell

是否可以在没有 Mac 的情况下为 iOS 制作 PhoneGap 应用程序?

为什么 Safari 在使用 iOS 6 设备进行远程调试时显示No Inspectable Applications?

动画 UILabel 字体大小更改

无法验证客户端 3000

如何从一个特定的视图控制器中隐藏导航栏

如何在 Swift 中更改按钮标题对齐方式?