强行打开可选项的优点是什么?

时间:2016-01-14 16:44:06

标签: swift performance null optional type-safety

如果变量是Optional,那么强行解开它的优势是什么。

class Button: UIButton {
    var title: UILabel? = nil
    required init?(coder aDecoder: NSCoder) {
        fatalError()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    func addTitle(text: String) {
        title = UILabel(frame: CGRect())
        self.addSubview(title!)
    }

}

let a: Button = Button(frame: CGRect())
a.addTitle("Hello World")

// Case 1
a.title?.text = "Goodbye"

// Case 2
a.title!.text = "Hello World"

问题

案例1 中,我知道它更安全但有任何性能改进或使用 案例2 的理由?

因此,如果我们知道 案例1 更安全,我们为什么要使用 案例2

4 个答案:

答案 0 :(得分:3)

根据评论,您的示例实际上并不有效。把它放在一边:强行展开意味着“我只用一个具体的价值工作;如果我没有,我想立即失败”。因此,通常优先使用nil值继续执行该部分代码,然后在因果关系遭到严重侵蚀后再遇到其他问题。

所以:它允许你明确谁有责任保证价值存在。

答案 1 :(得分:3)

在性能方面,强制和可选绑定/链接之间可能存在非常非常小的差别,因为可选版本可能在某处有额外的if

但是在讨论性能问题时,性能瓶颈来自代码的其他部分,例如非改进的循环,在很短的时间内发送的大量累积NSNotification,不必要的重绘用户界面等

因此,最好保持更安全的一面并使用可选的绑定/强制转换/链接,并专注于代码中增加实际性能损失的部分。即使在您编写代码时,该值仍保证为non-nil,将来可能会出现条件发生变化,并且您最终会遇到崩溃但您没想到它们会发生故障。发生。

Swift已经很容易处理选项,没有编写很多样板代码,你应该利用这些功能。

答案 2 :(得分:2)

使用隐式解包的Optional或使用Optional强行展开!的好(或至少是可防御的)原因:

  • @IBOutlet s:由于几个原因,这些通常是隐式展开的。您不希望每次访问它们时都必须手动解包它们。但更重要的是,如果您的网点没有正确连接,您想立即知道。
  • 如果值为nil,您有意识地决定要让应用崩溃的其他情况。例如,如果要从故事板中实例化视图控制器,并且需要成为UIViewController的特定子类MyViewController才能使您的应用程序正常运行,则可能强制使用它return vc as! MyViewController。这样你就可以马上发现有些东西已经关闭。

老实说,就我所知,就是这样。只是我自己的方法,但我保留!来声明@IBOutlet s。否则,99.999%的时间在可选链接情况下用if letguard?打开。还有其他方法可以知道值为nil。如果可选项无法解包,请向控制台输出一条消息,告知您失败。对我来说,简短的描述性消息比崩溃和unexpectedly found nil while unwrapping an optional value错误更容易调试。如果我希望程序失败,我仍然可以使用fatalError和描述性消息:

guard let x = someOptional else { fatalError("someOptional is nil in awakeFromNib.") }

通过为!预留@IBOutlet,每当我收到其中一个unexpectedly found nil while unwrapping an optional value错误时,我就会确切地知道在哪里找到问题的根源。我在界面构建器中查看我的@IBOutlet连接。坚持使用该策略,并使用其他工具来识别nil不应该使用的其他值,对我有用。

答案 3 :(得分:1)

一些替代方案(避免强行展开!)。尝试使用非零值a以及a包含nil的情况。

var a: String? = nil
a = "Hello World"

// Case 1 : nil coalescing operator
print(a ?? "a has value nil, let's not unwrap it!")

// Case 2 : if-let clause
if let a = a {
    print(a)
}
else {
    print("a has value nil, let's not unwrap it!")
}

// Case 3 : guard-let-else clause
func foo(a: String?) {
    guard let a = a else {
        print("a has value nil, let's not unwrap it!")
        return
    }
    print(a)
}
foo(a)