Swift中的可选项(使用方法)

本文旨在回答以下问题:在Swift中解开可选控件的最佳方法是什么? 为了回答这个问题,我们将探讨实际上是什么可选参数,以及Swift为何使用它们。 然后,我们将考虑几种方法,您可能希望以一致的样式在代码中将它们展开。

让我们首先确认我们对什么是可选的理解:可选实际上是Swift中的一种特殊类型 ,它在其中包装了其他类型。 为了说明这一点,请考虑以下事实:类型为StringString? 实际上是Swift中的两种不同类型。

需要说明的是: 字符串肯定会是初始化的字符串,另一方面,“ 字符串?”实际上是Optional ,这是一种特殊类型,需要对其进行“包装”才能使用。 如我们所见,“ Swift的类型系统通常在包装类型的名称后加上问号(?),而不是显示完整的类型名称”(参考编号:F)。

在表面上, Optional类型是具有两种情况的通用枚举:Optional.none和Optional.some(Wrapped),用于存储包装的值。

从本质上讲,然后Optional类型就像一个盒子 ,可以包含一个值,也可以不包含任何内容(零) 。 非常类似于经典游戏,一个人试图在一组洗过的杯子下面找到一个球,直到您真正提起其中一个杯子并在杯子下面看一下,在杯子下面是否会有东西并不清楚。

在尝试表示可能尚未为其分配值或不存在值的对象(即可能不存在值的情况)时,可以在Swift中使用可选选项

Swift创建了这个包装对象,该包装对象可能包含一个值,以便我们能够“ 拆开 ”该可选对象以访问其包含的值,或者在这种情况下, 它可能根本不包含任何值 ,如果我们不明智地尝试要“强制拆开”该选装件,将出现错误并可能崩溃(参考编号:C)。

C语言或Objective-C语言均未使用可选选项“ Objective-C中最接近的东西是能够从原本会返回对象的方法中返回nil的能力, nil意味着“缺少有效的对象”。 ,这仅适用于对象,不适用于结构,基本C类型或枚举值。 对于这些类型,Objective-C方法通常返回一个特殊值(例如NSNotFound )以指示不存在值。 这种方法假定方法的调用者知道要测试的特殊值,并且记住要进行检查。 Swift的可选参数使您可以指示任何类型都根本没有值,而无需特殊常量”(参考编号:C)。

“使用可选参数类似于在Objective-C中对指针使用nil ,但是它们适用于任何类型,而不仅仅是类。 可选参数不仅比Objective-C中的nil指针更安全和更具表达力,而且它们是Swift最强大的功能的核心”(参考编号:G)。

因此,在Swift语言中添加可选选项的论点集中在以下事实:它们强制执行良好的编程习惯(它们迫使程序员编写更明确的代码),并允许在编译时进行更好的代码检查(参考编号:L)。

“可选是Swift统一虚无表示的方式。 通过使用它们,我们失去了零消息传递的便利性和灵活性,但是获得了编译时检查,安全性以及处理相同问题的一致方法,而不论变量类型如何(参考编号:N)。

因此,从上面的内容中我们了解到,由于Optionals是一种特殊类型,并且基本上包含一个值或不包含任何值,我们不能直接使用它们,所以我们必须将它们拆开 (就像小时候一样,与您的新动作人物形象在圣诞节时一起使用,而无需先将其拆开)。 因此,让我们探索一下如何在代码中完成:

为了安全地解开可选选项,Swift社区中一种普遍且广受欢迎的方法是使用如下if let语句:

使用这样的方法称为“ 可选绑定”,因为我们创建了一个新属性,尝试将给定可选内容分配给该属性,但是如果不能(在上述示例中),我们将失败到我们的else语句。

安全解包的另一种方法是使用guard语句,例如,我们可以创建一个采用take和optional的函数,并使用guard let语句检查是否在传递给函数的optional中是否有任何内容:

如果里面没有什么可选项仍然可以,因为我们的警卫声明会掩盖我们的后背:

阻止导致问题的可选选项的一种聪明方法是通过“ nil-coalescing运算符” 提供默认值 ,或者在设置var或使其等于某些可选值(可能为nil)时在“ ??”之后放置默认值:

因此,如果Optional包含nil而不是由值填充,则可以使用此运算符为以后在代码中使用的内容提供默认值。

(编号:F)

可以安全使用强制展开的一种方法是,使用条件语法(如下面的示例)测试是否存在可选选项,以验证我们的可选选项不等于nil:

由于不包含值的swift可选项将具有特殊的nil值,因此可以使用if语句来检查对象是否包含值,如上面的代码段所示。 说了我们可以做到的之后,需要注意的是大多数开发团队不会使用这种方法。 原因是,如果公司代码准则完全排除了使用“!”(刘海)来展开可选内容的可能性,那么任何代码检查者通常都更容易发现强制展开的任何问题。

(参考编号:A&H)

正如保罗·哈德森(Paul Hudson)所说,它是可选的链接,“只有在可选元素具有值的情况下,才让您运行代码”,这样它就可以查询和调用当前可能为零的可选元素的属性,方法和下标。 如果可选变量包含一个值,则调用成功;或者,如果可选变量为nil,则调用将返回nil(参考号:G)

对此进行扩展:强制展开可选链和可选链之间的主要区别在于:“当可选链为nil ,可选链会优雅失败 ,而当可选链结为nil ,强制展开会触发运行时错误”(参考编号:G)。

在一个示例中可以更容易地看到它的工作:在下面的第一个示例中,当我们设置catsFaveFood时,在myCat中碰巧发现myCat的值已经设置为“ Fish”:

但是,我们也可以安全地在上面的摘要中评论我们的第3节,因为“可选链接”为我们处理了此问题:

使用强制展开几乎总是一个坏主意。 如果您在代码中找到以下示例(未添加nil的检查),则可能不正确:

let someConstant = opt!.property // CRASH!

当我们声明一个可选类型时,通常使用下面的代码将其声明为可选类型(这意味着我们必须对其进行拆包才能使用它):

var text: String?

但是我们也可以选择使用隐式展开

var text: String!

..这意味着以后无需拆包。

在幕后,值得注意的是, implicitly unwrapped optional实际上是一种类型为ImplicitlyUnwrappedOptional的枚举,而optional是具有Optional类型的枚举(Ref#:M)。

考虑到使用隐式展开的可选内容可能导致的问题,我们为什么要使用它?

好吧,如果您将某个属性声明为可选属性并且未使用隐式展开,那么每次尝试访问可选属性中的值时,都需要使用可选绑定或可选链接。 这可能会导致看起来很凌乱的代码,在该代码中,您经常需要在多个位置解包对象(参考编号:H)。

但是在某些情况下,由于我们是如何设置与笔尖或故事板的链接的,所以我们知道例如UI元素 将在视图生命周期中的某个时刻存在 。 因此,我们经常会看到类似插座之类的东西,当您控制从笔尖或情节提要中拖动并在ViewController中创建插座以使您能够访问UI项时,可能会创建此类插座:

注意: 对于带有插座的插座,也必须始终使用“弱”修饰符进行标记,因为它应该是视图而不是视图控制器,该指针应保持指向它们的强指针—否则将发生保留周期。

对于出口,我们从本质上知道它们将可用(在视图生命周期中的某个点之后),因此为了避免添加额外的检查,我们仅假设它们将在访问它们时被填充。

一般而言,对不是出口的事物使用隐式展开通常不是一个好主意,但是在某些情况下,例如在解码JSON时使用符合Codable协议的对象时,隐式解包Codable对象中的某些属性,以免总是解开这些属性(也许其中一个对象嵌套在另一个已经检查为nil的对象中)。

因此,从我们在本文中介绍的内容来看,是否有解开可选内容的最佳方法?

首先也是最重要的一点:除非在我们首先看到它们不是nil的情况下,否则不要在代码中强行打开可选项,除非我们已经看到了带有显式可选项的用例。

在我看来,理想情况下,您应该使用Optional Binding(如果让并保护let语句)。 这是因为实际上,“可选绑定”是最广泛接受的方法,因为它避免了在代码中完全使用任何形式的强制展开的需要,并且使查找有问题的展开时代码更易于查看。

答: https //stackoverflow.com/questions/25195565/how-do-you-unwrap-swift-optionals

B: https //hackernoon.com/swift-optionals-explained-simply-e109a4297298

C: https : //developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID309

D: https : //developer.apple.com/documentation/swift/optional

E: https : //www.youtube.com/watch?v=7a7As0uNWOQ

F: https : //www.youtube.com/watch?v=ZL8BFK8bVjk

G: https //docs.swift.org/swift-book/LanguageGuide/OptionalChaining.html

H: https //docs.swift.org/swift-book/LanguageGuide/TheBasics.html

F: https : //developer.apple.com/documentation/swift/optional

G: https //www.youtube.com/watch?v = fVaGY9wUZnQ

H: https //stackoverflow.com/questions/24006975/why-create-implicitly-unwrapped-optionals-since-that-implies-you-know-theres

我: https //cocoacasts.com/embracing-optionals-in-swift

J: https //cocoacasts.com/swift-fundamentals-working-with-optionals

K: https : //www.hackingwithswift.com/read/0/13/optional-chaining

L: https //stackoverflow.com/questions/35546224/what-makes-swifts-optional-safer-than-objective-cs-nil

M: https //krakendev.io/blog/when-to-use-implicitly-unwrapped-optionals

N: http //commandshift.co.uk/blog/2014/06/11/understanding-optionals-in-swift/


最初于 2018年6月16日 发布在 www.steveclarkapps.com 上。