可选类型
在 Swift 中,可选类型用来处理值可能缺失的情况,表示下面两种情况:
- 有值,你可以访问该值
- 没有值
在 Swift 中声明变量时,使用 ?
或 !
来表示声明的变量是可选类型。
let name:String?
var age:Int!
此时,变量 name
和 age
默认都是 nil
,表示空。
而 ?
和 !
的区别在于使用前者声明的变量所包含的值时,需要在变量后添加 !
符号来解析其所包含的值,而后者是隐式解析,不需要再添加 !
符号。
如下:
name = "John"
let tmpName:String = name!
age = "18"
let tmp:Int = age
当然,使用隐式解析声明的变量时,即使添加了 !
符号来强制解析其包含的值也不会报错。但是,需要注意的是,如果可选变量中并不包含值而进行了解析,即便是隐式的,也会报错,因为 nil
不能用于非可选的常量和变量。
除非确定变量赋值后便不可能为 nil
,否则不宜使用 !
符号声明可选变量。而在使用可选变量时,如果不能确定可选变量中的确包含值,那么不宜使用 !
符号进行解析。
可选链
在使用可选类型时,如果不确定它是否确实包含值,而又需要访问其可能包含的值的属性、方法或下标时,可以在可选值后添加一个 ?
符号,定义一个可选链。不同于使用 !
符号进行强制展开,该可选链不会因为无值可展开而发生运行时错误。
并且,可选链调用的返回结果同样是一个可选值,即便真实的属性或方法返回值并非可选类型,因为这些非可选类型会被包装成可选类型,不过对于已经是可选类型的结果并不会再进行包装。
如下面的例子:
class Person: NSObject {
let name:String
init(name:String) {
self.name = name
}
var apartment:Apartment?
}
class Apartment {
let unit:String
var address = ""
init(unit:String) {
self.unit = unit;
}
weak var tenant:Person!
func changeAdd(address:String) -> String? {
self.address = address
return address
}
}
func test() {
var person = Person.init(name: "John")
let apart = Apartment.init(unit: "A5")
person.apartment = apart
apart.tenant = person
if let isHas = person.apartment?.tenant?.apartment?.changeAdd(address: "shanghai")?.hasPrefix("shang") {
print(isHas)
}
}
在 Apartment
类中,属性 tenant
是隐式可选类型,但在 test
方法中,仍然可以在 tenant
后添加 ?
来构成可选链,当然这里也可以省去 ?
,但是如果同时 tenant
没有值时,程序便会报错。
如下:
func test() {
var person = Person.init(name: "John")
let apart = Apartment.init(unit: "A5")
person.apartment = apart
// apart.tenant = person
if let isHas = person.apartment?.tenant.apartment?.changeAdd(address: "shanghai")?.hasPrefix("shang") {
print(isHas)
}
}
而不省略 ?
构成的可选链会检查每一个可选值的取值结果,如果有一个可选值包含的值为 nil
,那么便直接返回 nil
。
将下面的代码单独成一行,便会发现,isHas
是的结果是 (Bool?)nil
,而从 hasPrefix
方法的定义可知,其返回类型为 Bool
,所以可以得知可选链中的每一个结点的返回结果如果是非可选值,也会被包装为可选值。
let isHas = person.apartment?.tenant.apartment?.changeAdd(address: "shanghai")?.hasPrefix("shang")