为什么我会使用无主的自我?

时间:2017-09-25 14:17:23

标签: ios swift swift3

iOS应用程序中出现以下模式:

class MyViewController: UIViewController {
    let myModel = MyModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        myModel.foo() { [***] in
            // use self here
        }
    }
}

class MyModel {
    public func foo(complete: () -> Void) {
        // do something
        complete()
    }
}

一致意见是使用[unowned self][weak self]代替[***],当你可以保证在完成时自我不会为零而在你完成时为弱不确定参考文献是否仍然有效 我不明白为什么我会冒险使用无主,也许我确信现在参考永远不会是零,但这可能在未来发生变化。我也可能忽略了一个边缘案例,错误发生了。我可以很容易地总是使用弱,并在封闭的顶部放一个警卫,以便能够使用自己没有!还是? 无主的用途是什么?它比弱+守卫更快吗?是语法糖吗?这似乎违背了Swift的保护开发人员免受可能导致崩溃的常见错误的理念。

4 个答案:

答案 0 :(得分:11)

unowned具有优于weak的边际性能优势,因为当对象消失时,运行时无需跟踪将其转换为nil的引用。

关于保留周期(好的,强参考周期),weakunowned都没有创建强引用(在ARC之前的术语中,既没有增加保留计数),所以没有危险实际上,这就是参考周期,这就是为什么你需要在闭包中为weak指定unownedself的原因。

此外,使用unowned,您可以将引用用作非可选项,因此您不必在闭包中放置任何代码来解包它。

除非有非常好的表现理由,否则我总是使用weak

在你的代码中注意,我认为没有必要,因为闭包没有转义,即函数调用foo中对它的引用在foo结束后不会持续存在范围。

答案 1 :(得分:1)

我认为使用unowned会增加风险,而不是使用弱自我。错误确实发生,它的一个例子是在视图控制器中启动API调用,让它等待响应到达并突然弹出视图控制器可能导致它被解除分配(如果没有强引用它)。当响应到来时,我们的视图控制器对象将消失,我们的应用程序将崩溃在我们的脸上。由我们来决定在哪个地方使用哪一个。

正如 Jeremy 所指出的那样,unowned没有责任跟踪引用计数,因此它在强弱方面具有如此轻微的性能优势。

答案 2 :(得分:0)

根据Swit Programming Guide: Automatic Reference Counting

  

无主参考应始终具有值。因此,ARC永远不会将无主引用的值设置为nil,这意味着使用非可选类型定义无主引用。

简而言之,weak是选项,其中unowned不是。

答案 3 :(得分:0)

在导航控制器中使用无主引用的简单示例:

class RegisterViewController: UIViewController {
    lazy var navigatinRightBarItemsCount: Int = { [unowned self] in
        guard let navigationController = self.navigationController else { return 0 }
        guard let topItem = navigationController.navigationBar.topItem else { return 0 }
        guard let rightBarButtonItems = topItem.rightBarButtonItems else { return 0 }
        return rightBarButtonItems.count
        }()

    override func viewWillAppear(_ animated: Bool) {
        print("Navigation bar right side items count: ", navigationRightBarItemsCount)
    }
}

这意味着必须初始化RegisterViewController,然后我们才能安全地获取自己。 navigationController并从此处获取项目计数。如果您尝试将其设置为[weak self],则XCode会抱怨,因为self(viewcontroller)可以为nil,因此我们必须使用unown。

另一个带有UIBarButtonItem的示例

lazy final private var filterNavigationBarItem: UIBarButtonItem = { [unowned self] in
    return UIBarButtonItem(image: #imageLiteral(resourceName: "filter_icon"),
                           style: .plain,
                           target: self,
                           action: #selector(segueToFilterJobs))
    }()

我们在这里看到什么?请参阅代表“ 接收动作消息的对象”的目标。这意味着接收动作消息的对象不能为nil,必须进行初始化。

drewagthis article.的一个很好的解释

  

您唯一真正想要使用[无主的自我]或[弱者]的时间   [self]是指您将创建一个强大的参考周期的时间。一个强壮的   参考周期是对象结束时存在所有权循环的情况   彼此拥有(可能通过第三方),因此他们   将永远不会被释放,因为它们都确保了每个   其他棍子。