十二.可选链
1.对于前面的学习的可选类型:Swift的所有类型默认不能接受nil值,如果程序想让某种数据类型接受nil值,则必须将这种数据类型包装成可选类型。——两种方法:在原有的类型后面加?后缀,要进行强制解析;在原有的类型后加!后缀,由Swift隐式解析。
2.可选链正是用于处理这里可选类型的属性、方法、下标等的。
3.为了更好的理解,直接从代码例子入手:
下面的定义了3个类,这3个类之间存在关联关系,而且程序使用了可选类型类维护它们之间的关联关系:
class Customer
{
var name = "xx顾客"
var emp : Employee?//注意这里有个问号----强制解析
init(name : String)
{
self.name = name
}
}
class Employee
{
var name = "xx职工"
var title = "销售"
var comp : Company!//注意这里有个感叹号----隐式解析
init(name : String, title : String)
{
self.name = name;
self.title = title
}
}
class Company
{
var name = "xx公司"
var addr = ""
init(name : String, addr : String)
{
self.name = name
self.addr = addr
}
}
3个类的关系是:顾客有一个专门为他负责的职工,职工是属于某个公司的。实例化如下:
var customer = Customer(name : "习大大")
var employee = Employee(naem : "马云", title : "销售")
customer.emp = employee
var company(name: "阿里巴巴", addr: "杭州")
employee.comp = company
//这里就可以获取到:为顾客习大大服务的职工所在的公司名称是:阿里巴巴
print("为\(customer.name)服务的职工坐在的公司名称是:\(c.emp!.comp.name)")//注意,emp后面有一个感叹号
4.上面程序中,因为Customer的emp属性类型是Employee?可选类型,因此在程序中使用Customer的emp属性必须使用感叹号进行强制解析。而Employee的comp属性是Company!可选类型,因此程序不需要强制解析,由Swift进行隐式解析即可。
5.对于上面的程序的来说,因为所有需要关联的地方都没有遗漏,所以上面程序可以正确的运行。但是对于下面的情况则会有不同的结果:
var c2 = Customer(name : "小明")
var emp = Employee(name : "小小明", title : "客服")
print("为\(c2.name)服务的职工所在的公司名称是\(c2.emp!.comp.name)")
var c3 = Customer(name : "小红")
print("为\(c3.name)服务的职工所在的公司的名称是:\(c3.emp!.comp.name)")
----对于c2来说,Employee实例所关联的Company为nil,因此程序在进行隐式解析可选类型时将会导致运行错误
----对于c3来说,c3连Employee的实例都没有关联,因此,程序会对c3.emp!进行强制解析得到nil,也会导致运行时出错
----上面两段代码,在编译时可以正常通过,但是运行时就会报错:fatal error
6.通过上面的会导致出错的例子可以看出,强制解析或隐式解析存在一个缺点:只要访问链中任何一次访问的返回值是nil,程序就会导致错误。
7.将上面访问链中强制解析的感叹号换成问号后缀,在隐式解析的后面也添加问号后缀,这就是可选链的访问方式。
8.可选链是一种更加“智能”的方式,可选链会自动判断程序访问的关联实例是否为nil:
(1)如果关联实例不为nil,可选链会自动解析可选类型所包装的值----就像隐式解析一样。
(2)如果关联的实例为nil,可选链不会导致运行时错误,可选链将返回一个nil。即,程序的结果为nil。
将上面5中的输出代码修改如下:
print("为\(c2.name)服务的职工所在的公司的名称是:\(c2.emp?.comp.name)")//输出为nil
print("为\(c3.name)服务的职工所在的公司的名称是:\(c3.emp?.comp.name)")//输出为nil
9.可选链不仅可以用于访问属性,也可以用于调用方法。举个栗子:在刚开始的Customer类增加以下代码:
//定义一个常量类型的emp数组,用于模拟系统中所有员工
let employees = {
Employee(name : "职工1", title : "销售1")
Employee(name : "职工2", title : "销售2")
Employee(name : "职工3", title : "销售3")
Employee(name : "职工4", title : "客服1")
Employee(name : "职工5", title : "客服2")
}
//定义一个方法,该方法可根据员工的名称返回对应的员工信息,返回值为可选类型
func findEmp(empName : String) -> Employee!----注意,这里有个感叹号
{
for emp int employees
{
if emp.name == empName
return emp
}
return nil
}
10.上面的程序中,调用Customer实例的findEmp方法是,如果进行强制解析或隐式解析该返回值,并用该返回值调用方法时就有可能导致运行时错误。但如果程序使用可选链就可以避免错误,使用可选链的代码如下:
c3.findEmp("嫦娥")?.info()
c3.findEmp("KoBe")?.info()
11.当下标返回值类型为可选类型时,下标的返回值同样有可能为nil,此时可对下标使用可选链。举个栗子:
var dict = [Int : Customer]()
dict[1] = Customer(name : "唐僧")
dict[2] = Customer(name : "悟空")
dict[3] = Customer(name : "八戒")
dict[4] = Customer(name : "沙僧")
dict[1]?.findEmp("白龙马")?.info()----第二个问号那里返回nil
dict[2]?.findEmp("白龙马")?.info()——第一个问号那里返回nil
网友评论