Swift 的可选(Optional)类型,用于处理值缺失的情况。可选表示"那儿有一个值,并且它等于 x "或者"那儿没有值"。
Swfit语言定义后缀?作为命名类型Optional的简写,换句话说,以下两种声明是相等的:
var optionalInteger: Int?
var optionalInteger: Optional<Int>
注意:在类型和 ?之间没有空格。
在这两种情况下,变量 optionalInteger 都是可选整数类型。
Optional
是一个含有两种情况的枚举,None
和 Some(T)
,用来表示可能有或可能没有值。任何类型都可以明确声明为(或者隐式转换)可选类型。当声明一个可选类型的时候,要确保用()
给 ?
操作符一个合适的范围。例如,声明可选整数数组,应该写成 (Int[])?
,写成 Int[]?
会报错。当你声明一个可选变量或者可选属性的时候没有提供初始值,它的值会默认为 nil
。可选项遵照 LogicValue
协议,因此可以出现在布尔环境中。在这种情况下,如果可选类型T?包含类型为T的任何值(也就是说它的值是 Optional.Some(T) ),这个可选类型等于 true
,反之为 false
。
如果一个可选类型的实例包含一个值,你可以用后缀操作符 !
来访问这个值,如下所示:
optionalInteger = 42
optionalInteger! // 42
注意:使用操作符
!
去获取值为nil
的可选变量会有运行时错误。
你可以用可选链接和可选绑定选择性执行可选表达式上的操作。如果值为nil,任何操作都不会执行,也不会有运行报错。
让我们来详细看下以下实例来了解 Swift 中可选类型的应用:
import Cocoa
var myString:String? = nil
if myString != nil {
print(myString)
}else{
print("字符串为 nil")
}
以上程序执行结果为:
字符串为 nil
可选类型类似于Objective-C中指针的nil值,但是nil只对类(class)有用,而可选类型对所有的类型都可用,并且更安全。
强制解析
当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号!
来获取值。这个感叹号表示"我知道这个可选有值,请使用它。"这被称为可选值的强制解析(forced unwrapping)。
实例如下:
import Cocoa
var myString:String?
myString = "Hello, Swift!"
if myString != nil {
print(myString)
}else{
print("myString 值为 nil")
}
以上程序执行结果为:
Optional("Hello, Swift!")
强制解析可选值,使用感叹号!
:
import Cocoa
var myString:String?
myString = "Hello, Swift!"
if myString != nil {
// 强制解析
print( myString! )
}else{
print("myString 值为 nil")
}
以上程序执行结果为:
Hello, Swift!
注意:使用
!
来获取一个不存在的可选值会导致运行时错误。使用!
来强制解析值之前,一定要确定可选包含一个非nil
的值。
自动解析
你可以在声明可选变量时使用感叹号!
替换问号?
。这样可选变量在使用时就不需要再加一个感叹号!
来获取值,它会自动解析。实例如下:
import Cocoa
var myString:String!
myString = "Hello, Swift!"
if myString != nil {
print(myString)
}else{
print("myString 值为 nil")
}
以上程序执行结果为:
Hello, Swift!
使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if
和while
语句中来对可选类型的值进行判断并把值赋给一个常量或者变量。
像下面这样在if
语句中写一个可选绑定:
if let constantName = someOptional {
statements
}
让我们来看下一个简单的可选绑定实例:
import Cocoa
var myString:String?
myString = "Hello, Swift!"
if let yourString = myString {
print("你的字符串值为 - \(yourString)")
}else{
print("你的字符串没有值")
}
以上程序执行结果为:
你的字符串值为 - Hello, Swift!
as
, as!
与 as?
的使用
-
as
keyword:Guaranteed conversion、 Upcasting
理解:字面理解就是有保证的转换,从派生类转换为基类的向上转型
实例:
// 将1转成float
let num = 1 as CGFloat
// dog转换到父类animal
class Animal {}
class Dog: Animal {}
let d = Dog()
d as Animal
-
as!
keyword:Forced conversion、 Downcasting
理解:字面理解就是有强项转换,即向下转型,子类(派生类)向父类转换,官方解释说这是一个不被保证的转换,可能会因为强转的失败而会导致崩溃。同时!
是一个陷阱的标志,就像⚠️一样,用起来存在一定危险性。
class Animal {}
class Cat: Animal {}
let animal :Animal = Cat()
let cat = animal as! Cat
-
as?
keyword:Optional、 Nil
理解:Swfit代码写一段时间后会发现到处都是 ? ,这预示着如果转换不成功的时候便会返回一个 nil 对象。成功的话返回可选类型值(optional),需要我们拆包使用。由于as?
在转换失败的时候也不会出现错误,所以对于如果能确保100%会成功的转换则可使用as!
,否则使用as?
// Dog、Cat和Animal的转换关系
class Animal {}
class Cat: Animal {}
class Dog: Animal
{
var name = "Spot"
}
let dog: Dog? = nil
dog?.name // 选择调用,返回空值nil
dog!.name // 强行调用,报错
let animal: Animal = Cat()
animal as? Dog // 猫转狗失败,返回nil
animal as! Dog // 猫强行转狗,失败报错
可选类型在错误处理中使用(try!
与try?
)
-
try?
try?会将错误转换为可选值,当调用try?
+函数或方法语句时候,如果函数或方法抛出错误,程序不会发崩溃,而返回一个nil
,如果没有抛出错误则返回可选值。
func someThrowingFunction() throws -> Int {
// ...
}
let x = try? someThrowingFunction()
x可能正常返回一个Int类型的值也有可能抛出一个错误异常,使用时对x用if let可选绑定判断
-
try!
使用try!
可以打破错误传播链条。错误抛出后传播给它的调用者,这样就形成了一个传播链条,但有的时候确实不想让错误传播下去,可以使用try!
语句
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
上述语句中在执行
loadImage
方法时如果执行失败,使用try!
来禁用错误传递,会有运行错误导致App崩溃