Swift中的安全性会影响性能吗?

时间:2017-08-13 19:32:29

标签: swift

在学习Swift的过程中,我看到了许多安全代码与不安全代码的情况。一个完美的例子是

as? as as!

as?,根据我的理解尝试输入强制转换,但如果它没有强制转换,则返回nil。

as!,根据我的理解,尝试输入强制转换,如果失败则崩溃。

我的问题是,为什么 as!,(和其他安全对应的不安全语法)存在?显然 as?是更好的选择。我能想到的唯一答案是,使用 as!对于编译器来说编译速度更快,因此主要是语法的优化。

我很想知道我的安全语法编译速度有点慢,因为性能对我很重要。

感谢您的时间。

4 个答案:

答案 0 :(得分:2)

这个问题基于一个错误的前提:as? vs as!的主要选择通常不是表现。当然,as!可能会更有效,但在优化构建中,差异通常可以忽略不计。

根据上下文选择as! vs as?

  • 如果演员表在运行时可能失败,那么您将使用as?。当然你添加代码来检查演员是否成功。

    当数据源是某些外部源(例如用户输入或网络请求)时,可能失败的强制转换的常见示例。用户可以将文本值粘贴到您只期望数值的字段中。外部Web服务器可能不可用,甚至可能以意外的格式返回数据。您希望使用as?来检测这些情况并优雅地处理它。

  • 但是如果演员阵容在运行时不可能失败,则使用as!。但是出于性能原因而不是出于清晰和编写简洁代码的原因,这样做的次数较少。

    不能失败的强制转换的一个常见示例是从故事板中检索单元格原型时,您知道基本类型是在Interface Builder中设置的,尽管Cocoa API无法知道这一点。添加大量代码检查以查看基类型是否设置正确(特别是因为这将是一个致命的编程错误,无论如何)并且导致代码具有大量语法噪声并且没有任何好处将是无效的。如果你没有正确地做到这一点,你很容易意外地抑制你在测试过程中真正想要清除的错误,这使得找到问题变得更加困难。这是as!语法的一个很好的用例。

答案 1 :(得分:1)

as!并非不安全,除非您之前的代码未能确保演员阵容无法失败。想象一下,您的代码已经验证了对象确实可以转换为特定协议的情况。如果由于某种原因您发现不创建该类型的新局部变量并将第一个变量强制转换为它是方便的,那么使用as!可以是合适的。

同样的逻辑适用于隐式解包的选项。由于实例化视图控制器时,无法分配IBOutlet属性(故事板尚未加载),该属性必须是可选的。但是当你知道故事板已经加载时,必须在整个班级中使用该属性作为可选项是令人厌烦的。事实上,如果找到故事板元素并进行分配时出现问题,则需要100%保证崩溃,以便开发人员始终能够发现并解决问题。

因此返回 as!,这引发了第二种情况:何时适合使用:每当崩溃是失败演员阵容最理想的结果时。

所以这不是关于编译器的速度。这是关于代码逻辑的便利性。有适当的时间使用它,并且在那些时候,它是一种更紧凑,更易于阅读的表示逻辑目标的方式。

答案 2 :(得分:0)

如你所说,as!几乎不应该使用。但是,在某些情况下,由于遗留问题,编译器不知道应该是什么类型,即使开发人员也这样做。其中一个例子是NSCopying协议。因为Objective-C不像Swift那样严格类型安全,copy()会返回id,它在Swift中桥接到Any。但是,当您使用copy()mutableCopy()和朋友时,您通常会确切地知道您将从中获得什么类型,因此as!通常用于强制转换为正确的类型

let aString: NSAttributedString = ...
let mutableAString = aString.mutableCopy() as! NSMutableAttributedString

答案 3 :(得分:0)

您可以通过编译类似

的内容自行调查此问题
func f(a: Any) -> Int {
    (a as! Int) + 5
}

VS。

func f(a: Any) -> Int {
    ((a as? Int) ?? 3) + 5
}

使用Swift 4编译器,在此Swift代码上运行swiftc -O -emit-assembly会产生非常相似的输出,这应该与您对as!如何工作的理解以及如果它不是一部分我们将如何实现它语言:

func forceCast<T>(_ subject: Any) -> T {
    return subject as? T ?? fatalError("Could not cast \(subject) to \(T)")
}

值得注意的是,正如SmartCat已经提到的那样,as!在Swift编译器作者定义该词的意义上实际上并不“不安全”;因为它像as?一样,实际上专门检查subject的类型。迅速投入一种不安全的快速感觉力量;不出所料,它被称为unsafeBitCast;并相当于C / Objective-C演员;它不会检查类型,只是假设你知道自己在做什么。它会比as快吗?毫无疑问。

所以,回答你的标题问题:是的,安全在Swift中有成本。硬币的另一面是,如果你编写的代码可以避免强制转换和可选性,那么Swift可以(理论上)比不那么强大的安全保证的语言更积极地优化你的代码。

回答你的实际问题;在性能方面,as?as!之间没有区别。

其他人已经涵盖了as!存在的原因;它是这样你可以告诉编译器“我无法解释你为什么,但这将永远有效;相信我。”