- 可选类型 (Optionals)
值可能不存在的情况下,你可以使用可选类型。 一个可选类型代表两种可能性:要么它有值(你可以通过解包来访问该值), 或者没有值。
Note: 在
C
或Objective-C
中不存在可选类型的概念。 在OC
中和可选类型这个概念最类似的是: 一个对象要么返回确定的值要么返回nil,其中nil表示“对象不存在”。然而这种方法仅适用于对象,并不适用于结构体、C
的基本类型以及枚举。 对于这些类型,OC
方法通常返回一个特殊值(例如NSNotFound
)来表示没有值。 这种机制假设了方法调用者知道存在一个特殊的值,而且会通过这个值来检测方法的结果。Swift
的可选类型可以让你表示任意类型的值缺失,并不需要特殊值。
这有一个例子说明了如何使用可选类型来处理不存在的值。Swift
的Int
类型有一个String类型的值转换成Int类型的初始化方法。 但是,并不是每个字符串都可以转换为Int类型。 字符串"123"
可以转换为数值123
,但字符串hello
,world
明显没有数字值可转换为Int
。
以下的示例使用这个初始化方法尝试将一个String转换为Int:
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber被转换为类型"Int?",即"可选类型Int"
- Nil
通过赋值nil
,你可以将一个可选类型设置为无值状态:
var serverResponseCode:Int? = 404
// serverResponseCode包含一个具体的Int值,即404
serverResponseCode = nil
// serverResponseCode现在不包含任何值
NOTE:
nil
不能和非可选类型的常量和变量一起使用。 如果你的代码中的常量或变量在某些情况下需要以没有值的状态运行,那你应该始终将其声明为可选类型。
如果你定义了一个可选类型的变量, 但是不设置默认值,那么该变量的值将自动设置为nil:
var surveyAnswer: String?
// surveyAnswer is automatically set to nil
NOTE:
Swift
中的nil
不同于OC
中的nil
。 在OC
中,nil
是一个指向不存在的对象的指针。 在Swift
中,nil
不是指针, 它是一个不存在值的特定类型的。 任何数据类型的可选类型都可以设置为nil
,而不仅仅是对象类型。
- If语句和强制解包 (If Statements and Forced Unwrapping)
你可以通过使用if语句比较可选类型和nil
,进而确定这个可选类型是否包含具体的值。你可以使用等于 运算符== 或 不等于 运算符!=执行比较。
如果一个可选类型有一个值,即它被认为是“不等于”nil
:
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
// Prints "convertedNumber contains some integer value."
一旦你确定可选类型确实有值,你可以通过在可选类型名称的末尾添加感叹号(!)来访问其包含的值。这个感叹号如同在宣称:“ 我知道这个可选类型肯定有值,请使用它。” 这被称为可选类型的强制解包:
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
// Prints "convertedNumber has an integer value of 123."
NOTE:
使用 (!) 时,访问不存在值的可选类型会触发运行错误, 所以在使用(!) 强制解包前, 要始终确保可选类型包含了非空的值。
- 可选绑定 (Optional Binding)
你可以使用可选绑定来确定可选类型是否包含值,如果这样做,你必须把这个绑定的值用作临时常量或变量。可选绑定可以与if-while
语句一起使用,以检查可选类型中的值,并作为这个操作的一部分将该值提取为常量或变量。if-while
语句在控制流(Control Flow)中有更详细的描述。
为if
语句编写可选绑定如下所示:
if let constantName = someOptional {
statements
}
你可以使用可选绑定重写 Optionals 部分的possibleNumber
示例,而不是使用强制解包:
if let actualNumber = Int(possibleNumber) {
print("The string \"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {
print("The string \"\(possibleNumber)\" could not be converted to an integer")
}
// Prints "The string "123" has an integer value of 123"
你可以在单个if
语句中按你的需求包含多个可选绑定和Boolean
条件,并以逗号分隔。如果可选绑定中的任何值为nil或任何Boolean
条件为false
,则整个if语句的条件被认为是false
。以下第二段if代码和第一段是等效的:
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
// Prints "4 < 42 < 100"
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
// Prints "4 < 42 < 100"
- 隐式解包可选类型 (Implicitly Unwrapped Optionals)
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 要求加上!来解包
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要加上!也可以解包
- 错误处理 (Error Handling)
你可以使用错误处理来应对你的程序在执行过程中可能遇到的错误。
与可选类型相反,错误处理可以通过值的存在或不存在来表示一个function的成功或失败,允许你确定error的根本原因,如有必要,它还能将error传送到程序的另一部分。
当方法遇到错误条件时,会抛出一个error。 该方法的调用者可以捕获错误并作出适当的响应。
func canThrowAnError() throws {
//这个函数可能会抛出一个错误
}
一个函数通过在其声明中包含throws
关键字来说明它可以抛出异常。 当你调用一个可以抛出异常的函数时,你可以在表达式中添加try
关键字。
Swift会自动将错误传送到当前作用域之外,直到被catch
语句处理
do {
try canThrowAnError()
// no error was thrown
} catch {
// an error was thrown
}
do语句创建一个新的包含范围,它允许将错误传送到一个或多个catch子句。
以下是一个示例,说明如何使用错误处理来响应不同的错误条件:
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
- 断言
Assertions
和先决条件Preconditions
断言和先决条件之间的区别在于被执行的时间点有所不同:断言仅在调试版本中执行,但在调试和发布版本中先决条件都会被执行。 在发布版本中,断言内的条件不再被执行。 这意味着你可以在开发过程中使用尽可能多地使用断言,因为这并不会影响发布版本的性能。
用断言进行调试:
通过从Swift
标准库调用assert(_:_:file:line:)
方法,你写下一个断言。 你将一段文字和一个结果为true
或false
的表达式赋值给这个方法,如果表达式的结果为false
,则显示这段文字。 例如:
let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
// This assertion fails because -3 is not >= 0.
在这个例子中,如果age> = 0
的值为true
,那么代码继续执行,即age
为正值。 如果age
为负值,如上面的代码所示,age> = 0
为false
,断言失败,终止应用程序。
你可以省略断言发布的文字——例如当它只是一个单调的重复条件。
assert(age >= 0)
如果代码已经检查了条件,则使用assertionFailure(_:file:line:)
方法来标明断言失败了。 例如:
if age > 10 {
print("You can ride the roller-coaster or the ferris wheel.")
} else if age > 0 {
print("You can ride the ferris wheel.")
} else {
assertionFailure("A person's age can't be less than zero.")
}
当条件有可能为false
的时候使用先决条件,但是必须确保你的代码会继续执行。 例如,你可以使用先决条件来判断下标是否越界,或者检查方法是否接收到一个有效的值。
通过调用precondition(_:_:file:line:)
方法你可以编写先决条件。 你需要给此方法赋值一个表达式,其计算结果为true或false,如果条件的结果为false
,则显示一段文字(也是由你赋值)。 例如:
// In the implementation of a subscript...
precondition(index > 0, "Index must be greater than zero.")