题 是什么让Swift的“可选”比Objective-C的“nil”更安全?


苹果似乎声称 那个 Optional 输入Swift比安全更安全 nil 在Objective-C中,但我不明白为什么会这样。

实施中有哪些显着差异 Optional比...更安全 nil,这将如何影响我的代码?


13
2018-02-22 05:14


起源


Swift在使用Optional之外不支持nil。 Optional可以包含nil,而non-Optional不能包含nil。如果使用“!”将变量声明为隐式展开,如果变量在使用时包含nil,则会出现异常。因此,当您不期望它时,您不必处理包含nil的“魔法”变量。 - Michael
@Michael你的评论是一个答案。 - Dmitri Pavlutin


答案:


我总是检查变量是否是 nil 在我使用它之前避免问题。但是,它仍然偶尔发生一个值可能会出现 nil令我惊讶的是 - 或者有时我只是忘了检查。

我在Swift中编写越来越多的代码后,我发现使用可选变量确实提供了很多方便,以避免忽略检查 nil 值。我真的不记得任何崩溃所致 nil 变量访问(除非我强制解包某些变量;所以除非你知道你在做什么,否则不要强制解包)。

此外,我曾经在很多地方写过很多像这样的代码:

if (obj != nil) {
    obj.property = ...
}

现在我可以简单地做到

 obj?.property = ...

代码现在看起来干净利落。你也不喜欢吗?


3
2018-02-22 07:21



这是一个非常糟糕的例子,因为obj.property = ...在Objective-C中运行得很好,什么都不做。 - gnasher729
我不是指Objective-C。这只是大多数编程语言的一般情况。例如,在Lua中试试这个。崩溃! - Joe Huang
这个问题已经改变了。当我回答这个问题时,我认为这个问题并未提及Objective-C的nil或者将Swift与Objective-C进行比较。必须合并或更改此问题。它失去了初衷。 - Joe Huang


一般来说,在编程中我们想要避免没有价值的变量(null 要么 nil)因为使用它们经常导致未定义的行为(异常,错误,崩溃)。

例如,这是一种常见的做法 Array 引用设置为空数组而不是 nil。在一个空数组我们可以使用所有 Array 方法,例如, indexOf 要么 count。使用它们 nil 会导致崩溃。

Optionals允许我们指定某些变量永远不会为空,因此我们可以安全地使用它们,编译器会检查它 nil 永远不会分配给他们。此外,编译器强制执行从optionals到非optionals的每次转换都是显式的(我们总是检查 nil 需要的时候)。

所以答案是选项:

  1. 实施良好的编程实践。
  2. 允许在编译时进行更好的代码检查

从而防止编程错误。

另请注意,您应尽可能避免使用选项。期权的最大力量是大多数变量不是期权。


2
2018-02-22 07:35



你能详细说明你的最后一句话“期权的最大力量是大多数变量都不是期权的事实。”? - Joe Huang
@JoeHuang这很简单。如果你的所有变量都是可选项,那么你就会回到没有选项的世界。一切都可以 nil。期权的力量是限制 nil 到特定的图书馆。 - Sulthan
我认为在考虑异步编程时有更多的选项。我不知道如何使大多数变量不是可选项。 - Joe Huang
@JoeHuang异步编程没有更多的选项。这都是关于编程风格的。当然,你不能完全避免选项,但你应该尽量减少它们的使用,否则你没有从中获得任何东西。 - Sulthan
“使用 [indexOfObject: 要么 count] 上 nil 会导致崩溃“嗯,不是在ObjC。 - Josh Caswell


它变得“安全”,因为它迫使程序员编写更明确的代码。

  • if let ... 和 guard 语法明确地说“只有在存在这些变量的值时才执行此操作”。
  • ! 如果变量是,语法会使程序崩溃 nil 当程序员没想到的时候 nil

相比之下,Objective-C的调用方式 nil 无操作 可能 让程序继续执行直到这样的程度 nil 是不能接受的。一个常见的例子是 nil  NSString 变量。许多API调用很满意 nil  NSString 除了建造时 NSAttributedString (它不会接受 nil  NSString 参数和崩溃你的应用程序)。因此,当你得到一个 NSString 变量意外变成了 nil,可能会等一段时间,直到你的应用程序崩溃,因为它试图用它构建一个属性字符串 nil 值。

有关Optionals试图解决的问题的更完整说明,请考虑 此帖由Daniel Jalkut于2010年回归。这是在Swift之前写的。


2
2018-02-22 07:26





在Objective-C中,您可以定义没有值的变量。如果要在分配值之前使用该变量,则会得到未定义的行为(这非常糟糕)。相反,swift可以防止对象值未知的情况。


-2
2018-02-22 05:21



自几年前引入ARC以来,任何指向Objective-C对象的指针都会自动初始化为nil。没有未定义的行为。如果您打开合理的编译设置,如果您尝试使用未初始化的变量,则代码将无法编译。 - gnasher729