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)
}
注意:通过可选链接访问可选值上的下标时,您将问号放在下标的括号之前,而不是之后。

