### Swift 可选型
可选类型用来表示值缺失的情况。我们可以在具体的值与 `nil` 之间做一个选择。
### 可选类型定义
```
var x : Int?
var y : Int
y = 10
print("\(x) -- \(y)") // 输出:nil -- 10
```
> `Int?` 与 `Int` 是两种完全不同的数据类型,前者为整型的可选行,后者是整型。
如果我们不给 `y` 赋值的话,程序将抛出错误。如下图:
![](image/WX20161209-105334.png)
因为如果声明了一个可选变量或者常量而没有赋值,则默认为 `nil` ,`nil` 不能用于非可选的常量或者变量。
其次,声明了一个非可选型的常量或者变量并没有赋值的之前,当我们输出的时候会抛出异常。
### 可选型的取值
#### 使用`!`进行强制解包
当确定可选类型确实包含值之后,可以在可选的名字后⾯加⼀个感叹号( `!` )来获取值。这个感叹号表⽰“我知道这个可选有值,请使⽤它。”这被称为可选值的强制解析。
```
"The errorCode is " + errorCode! // The errorCode is 404
```
> **注意:** 这种写法是在明确知道了可选型不等于 `nil` 的情况下使用。如果可选型的值为 `nil` 则会抛出 **fatal error** 致命错误。
#### 判断不是 `nil`
解包前对数据进行判断,如果不等于 `nil` 则进行解包操作。
```
var errorCode: String? = "404"
if errorCode != nil {
"The errorCode is " + errorCode!
}else{
"No Error"
}
```
#### `if-let` 解包
还可以给解包的值使用 `if let` 语句进行赋值。
```
var errorCode: String? = "404"
if let upwrappedErrorCode = errorCode { // 允许解包的常量名和可选型的名字一致
"The errorCode is " + upwrappedErrorCode
}else{
"No Error"
}
```
> 当然也可以使用 `if var` 的方式对可选型进行解包,不过通常在大多数的情况下,我们对一个可选性只是对其解包读取值,并不会去修改可选型的值。
#### 可以使用相同的变量名
也可以将上面的常量 `upwrappedErrorCode` 允许使用和 `errorCode` 一致的名称。
```
var errorCode: String? = "404"
if let errorCode = errorCode {
"The errorCode is " + errorCode
}else{
"No Error"
}
```
> 这种解包方式只能在 `{}` 中访问 `errorCode` 常量。在其他地方访问 `errorCode`变量依然是可选型。
#### 使用 `if-let` 同时解包多个变量
如果存在两种或者多种需要解包判断的情况,我们可以使用更加优雅的写法
```
var errorCode: String? = "404"
var errorMessage: String? = "Not Found"
if let errorCode = errorCode ,
let errorMessage = errorMessage {
"The errorCode is " + errorCode + "\nThe errorMessage is " + errorMessage
}
// 以上写法等同于
if let errorCode = errorCode {
if let errorMessage = errorMessage {
"The errorCode is " + errorCode + "\nThe errorMessage is " + errorMessage
}
}
```
还可以新增一些判断条件,如下:
解包两个可选型,并判断 `errorCode` 的值是否等于 404 。
```
if let errorCode = errorCode ,
let errorMessage = errorMessage , errorCode == "404" {
"page not found"
}
```
#### 可选型 Chaining
```
var errorMessage: String? = "Not Found"
errorMessage?.uppercased()
```
虽然 `errorMessage` 是一个可选型,这里尝试对它进行解包,如果解包成功(即不等于 `nil`)那么对他进行 `uppercased()` 操作;如果解包失败则不回执行 `uppercased()` 操作。
如果可选型 `errorMessage` 等于 `nil` ,则会返回 `nil`。
逻辑等同于如下写法
```
var errorMessage: String? = "Not Found"
if let errorMessage = errorMessage {
errorMessage.uppercased()
}
```
另一种写法
```
errorMessage!.uppercased()
```
将可选型 `errorMessage` 进行强制解包,并调用 `uppercased()` 操作,如果可选型 `errorMessage` 等于 `nil` 将会抛出 **fatel error** 致命错误,这种写法一般情况下是不安全的,也是不推荐的。
```
var uppercaseErrorMessage = errorMessage?.uppercased() // 变量 `uppercaseErrorMessage` 是一个可选型
```
```
if let errorMessage = errorMessage?.uppercased() {
errorMessage
}
```
> 上面的写法将解包和调用操作以及赋值基于一体,使逻辑更加清晰,减少代码的出错率。
#### 可选型 `Nil-Coalesce`
如下需求: `message` 变量的值待定,如果 `errorMessage` 可选型的值不等于 `nil` 时,变量 `message` 的值将等于 `errorMessage` 可选型解包后的值,否则将被赋值为 `no error`
```
var errorMessage: String? = nil
let message: String
if let errorMessage = errorMessage {
message = errorMessage
}else{
message = "no error"
}
```
我们可以使用三元运算符进行改写(返回可选型解包后的值)
```
let message2: String = ( errorMessage != nil ) ? errorMessage! : "no error"
```
也可以使用 Swift 更简洁的方法(返回可选型解包后的值)
```
let message3 = errorMessage ?? "no error"
```
### 可选型在元组中的使用
#### 将元组中的某个单元设置为可选型
```
var error: ( errorCode: Int , errorMessage: String? ) = ( 404 , "Not Found" )
print(error) // (404, Optional("Not Found"))
error.errorMessage = nil // 将元组的第一个分量设置为 `nil`
print(error) // (404, nil)
```
#### 将整个元组设置为可选型
```
var error2: ( errorCode: Int , errorMessage: String )? = ( 404 , "Not Found" )
// error2.errorMessage = nil // 这样设置会报错
error2 = nil // 这样操作是允许的
```
#### 将元组中的某个值以及整个元组都设置为可选型
```
var error3: ( errorCode: Int , errorMessage: String? )? = ( 404 , "Not Found" )
```
### 可选型的一些实际应用
#### 获取用户输入的年龄
```
var ageInput: String = "19"
var age = Int( ageInput ) // 将用户输入强制转换成整型
if let age = age , age < 20 {
print("You're a teenager!")
}
```
#### 字符串字串范围
```
var str = "Hello"
str.range(of: "o") // 4..<5
str.range(of: "is") // nil
```
### 隐式可选型
隐式可选性使用`!`来声明,相比于可选型的不同是,这种类型的变量或者常量**可以不使用解包就读取变量或者常量的值而直接使用。** 基本用于类的创建时属性的定义。
```
var errorMessage: String! = nil
errorMessage = "Not Found"
"The message is " + errorMessage
```
> 这种可选型在使用的时候可以不解包,直接使用,这种隐式可选性是不安全的,因为我们不需要解包就可以使用,当可选性的值是nil的时候讲会给程序带来error
```
class City {
let cityName: String
unowned var country: Country
init(cityName: String, country: Country) {
self.cityName = cityName
self.country = country
}
}
class Country {
let countryName: String
var capitalCity: City! // 隐式可选性
init(countryName: String, capitalCity: String) {
self.countryName = countryName
self.capitalCity = City(cityName: capitalCity, country: self)
}
func showInfo() {
print("This is \(countryName)")
print("The capital is \(capitalCity.cityName)")
}
}
let china = Country(countryName: "中国", capitalCity: "北京")
china.showInfo()
```
- 学习笔记
- 基础
- 基本类型之整型
- 基本类型之浮点型
- 基本类型之布尔类型以及简单的 if 语句
- 基础类型之元组
- 基本类型之其他
- 运算符
- 基础运算符
- 比较运算符、逻辑运算符
- 三元运算符
- 范围运算符for-in
- 逻辑控制
- 循环结构
- 选择结构
- 字符串
- Character和Unicode
- String.index 和 range
- 可选型
- 容器类
- 数组初始化
- 数组基本操作
- 字典初始化
- 字典基本操作
- 集合初始化
- 集合基本操作
- 函数
- 闭包
- 枚举
- 结构体
- 类
- 文档注释
- 属性和方法
- 下标和运算符重载
- 拓展和泛型
- 协议
- 其他
- Swift 3.0 For 循环
- Swift 随机数的生成
- IOS开发玩转界面 UIKit
- UILable 文本显示控件
- UIButton 简单的交互控件
- UIImageView 图片控件
- UISearchBar 搜索控件