Swift可选链
Swift Optional Chaining是一个非常有用的功能。
可选是Swift中包装原始类型的一种类型,通常用于防止空值。
有关Optionals的更多详细信息,请在继续之前参考本教程。
Swift可选链
可选链接是对可选值链接调用的过程,以便它可以优雅,简洁地处理展开操作,而不会产生运行时错误。
顾名思义,它将多个查询链接在一起。
但是使用if let
,guard let
和隐式解包也是可以实现的。
那么,对可选链接有何需求?
让我们先来看一下Playground中的示例,而无需带来"可选链接"。
没有可选链接
假设我们有以下程序:
class University { var city: City? var universityName: String = "San Francecon Institute of Technology" } class City{ var cityName: String? var college: College? } class College{ var discplines = [Discpline?]() var numberOfStreams : Int { return discplines.count } } class Discpline{ var discplineName: String? var student : Student? } class Student{ var name: String? var discpline : Discpline init(currentDiscpline: Discpline) { self.discpline = currentDiscpline } func printDetails() ->String { return "Student Details:\n Name:\(name ?? "Na") \n Discpline: \(discpline.discplineName ?? "NA")" } }
每个类都包含以下类的实例。
所有实例均定义为可选。
"大学"类拥有一个" Discpline"类对象的数组。
让我们实例化每个类。
var university = University() var myCity = City() myCity.cityName = "Bangalore" var myCollege = College() var csDiscpline = Discpline() csDiscpline.discplineName = "Computer Science" var meDiscpline = Discpline() meDiscpline.discplineName = "Mechanical Engineering" myCollege.discplines = [csDiscpline,meDiscpline] var myStudent = Student(currentDiscpline: csDiscpline) myStudent.name = "Anupam"
使用隐式展开让我们使用隐式展开(!)从类中获取和检索属性和函数。
university.city = myCity university.city!.college = myCollege university.city!.college!.discplines = [csDiscpline,meDiscpline] university.city!.college!.discplines[0]!.student = myStudent var finalString = university.city!.college!.discplines[0]!.student!.printDetails()
看起来还好但是我们从Swift的Optionals教程中知道,隐式展开可能会导致运行时崩溃,因为它会在不检查是否为零的情况下解开可选的内容。
在上面的代码中,如果将myStudent设置为nil,则将导致CRASH。
university.city!.college!.discplines[0]!.student = nil var finalString = university.city!.college!.discplines[0]!.student!.printDetails() //crash since student is nil
让我们尝试使用if let
/if var
。
if var uCity = university.city { uCity = myCity if var uCollege = uCity.college { uCollege = myCollege uCollege.discplines = [csDiscpline,meDiscpline] if var uDiscpline = uCollege.discplines[0] { if var uStudent = uDiscpline.student { uStudent = myStudent print(uStudent.printDetails()) } } } }
嵌套太多!这也仅仅是为了设置值并以非常基本的代码打印结果,而每个类中几乎没有几个属性。
这是低效的。
使用guard var让我们使用guard var做同样的事情。
func usingGuard(){ guard var uCity = university.city else{ print("City is nil") return } uCity = myCity guard var uCollege = uCity.college else{ print("College is nil") return } uCollege = myCollege uCollege.discplines = [csDiscpline,meDiscpline] guard var uDiscpline = uCollege.discplines[0] else{ print("Discpline is nil") return } guard var uStudent = uDiscpline.student else{ print("Student is nil") return } uStudent = myStudent print(uStudent.printDetails()) } usingGuard() //prints //Student Details: //Name:Anupam //Discpline: Computer Science
这比var更好,但仍然有太多条件检查。
隐式包装简洁明了,但很危险,因为它在包装前并未检查可选值。
这是"可选链接"为我们提供帮助的地方。
这是强制展开的另一种更好的形式。
在可选链接中,我们只需要将!.
替换为?.
。
可选链接如何工作
可选链接是在可选值上完成的。
它返回包装为Optional的所需值。
如果optional为nil,则返回Optional(nil)
。
可选链接始终为您提供可选选项,从而消除了运行时崩溃的机会。
因此有两件事:
如果通过"可选链接"检索的类型不是可选的,则在完成可选链接后,该类型将变为可选。
如果类型已经是可选的,那么它将仅保持可选。
它不会像Optional(Optional(Optional(String)))
那样嵌套。
使用可选链接实施
以下代码实现了可选的链接。
university.city = myCity university.city?.college = myCollege university.city?.college?.discplines = [csDiscpline,meDiscpline] university.city?.college?.discplines[0]!.student = myStudent var finalString = university.city?.college?.discplines[0]?.student?.printDetails() print(finalString)
现在定义了printDetails()返回一个String。
可以?没有。
它返回Optional(String),因为Optional Chaining用可选的包装了返回的值。
通过可选链接访问下标调用
将Discpline类更改为:
class College{ var discplines = [Discpline?]() var numberOfStreams : Int { return discplines.count } subscript(i: Int) -> Discpline? { get { return discplines[i] } set { discplines[i] = newValue } } }
多亏了下标,我们可以摆脱纪律对象的调用。
if let discpline0 = university.city?.college?[0]?.discplineName { print(discpline0) }
注意:通过可选链接访问可选值上的下标时,您将问号放在下标的括号之前,而不是之后。