可选项
- 可选项,一般也叫可选项类型,它允许将值设置为nil;
- 在类型名称后面加上
?
,来定义一个可选项;
强制解包
- 可选项是对其他类型的一层包装,可以将它理解为一个盒子;
- 如果可选项的值为nil,那么其是一个空盒子;
- 如果可选项的值不为nil,那么盒子中装的是被包装类型的数据;
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//默认值为nil
var age: Int?
age = 10 //age可以存储Int数据
age = nil //age可以存储nil
}
}
- 定义一个可选项类型age,没有初始化,则默认值为nil;
- age可以存储Int数据,也可以存储nil;
- 如果要从可选项中取出被包装的数据,需要使用感叹号
!
,进行强制解包;
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//默认值为nil
var age: Int? = 30
age = 40
let count: Int = age!
print(count)
}
}
- 如果对
值为空nil的可选项进行 强制解包,将会产生运行时错误
判断可选项是否包含值--使用if -- else
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//num是可选项类型
let num = Int("123")
if num != nil{
print("字符串转换成功 \(num!)")
}else{
print("字符串转换失败")
}
}
}
-
Int("123")
将字符串转换成整数,有可能转换失败返回nil,所以其返回值是一个可选项类型,在其不为空的情况下才能强制解包;
判断可选项是否包含值--使用switch -- case
func test() -> Void {
let num = Int("123")
switch num {
case let v?:
print("num有值",v)
default:
print("num为nil")
}
}
-
case let v?:
表示可选项num若不为nil,会自动解包将被包装的值赋值给常量v,所以v是Int类型;
自动解析
- 在定义可选项时,直接使用
! 替代 ?
,那么在解包使用数据时,可以省略!
var myString:String!
myString = "Hello, Swift!"
if myString != nil {
print(myString)
}else{
print("myString 值为 nil")
}
可选项绑定
- 使用
可选项绑定
来判断可选项是否包含值;
- 如果包含值就自动解包,把值赋值给一个临时的常量let或者变量var,并返回true;
- 否则直接返回false;
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let num = Int("123") {
print("字符串转换成功 \(num)")
}else{
print("字符串转换失败")
}
}
}
import UIKit
enum Season : Int {
case spring = 1,summer,autum,winter
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let season = Season(rawValue: 6) {
switch season {
case .spring:
print("春")
default:
print("其他")
}
}else{
print("枚举不存在")
}
}
}
-
Season(rawValue: 6)
其返回值也是可选项类型,所以可以使用可选项绑定;
等价写法
import UIKit
enum Season : Int {
case spring = 1,summer,autum,winter
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let first = Int("123") {
if let second = Int("234") {
if first < second {
print("\(first) -- \(second)")
}
}
}
//逗号隔开
if let first = Int("123"),
let second = Int("234"),
first < second {
print("\(first) -- \(second)")
}
}
}
while循环中使用可选项绑定
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let strs = ["10","20","abc","-20","30"]
var index = 0
var sum = 0
while let num = Int(strs[index]),num > 0 {
sum += num
index += 1
}
print(sum)
}
}
-
Int(strs[index])
是可选项类型,则使用可选项绑定,且满足是正数,才能进行相加操作;
空合并运算符??
- a ?? b
- a是可选项类型;
- b是可选项,也可以不是可选项类型;
- a和b的存储类型必须相同;
- 如果a不为nil,就返回a;
- 如果a为nil,就返回b;
- 如果b不是可选项,返回a是就是自动解包;
import UIKit
enum Season : Int {
case spring = 1,summer,autum,winter
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let a: Int? = 1
let b: Int? = 2
let c = a ?? b
print(c) //Int? Optional(1)
let a: Int? = nil
let b: Int? = 2
let c = a ?? b
print(c) //Int? Optional(2)
let a: Int? = nil
let b: Int? = nil
let c = a ?? b
print(c) //Int? nil
let a: Int? = 1
let b: Int = 2
let c = a ?? b
print(c) //Int 1
}
}
- 根据上面
??
的用法规则,可以确定常量c的数据类型及数值;
多个空合并运算符?? 一起使用
import UIKit
enum Season : Int {
case spring = 1,summer,autum,winter
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let a: Int? = 1
let b: Int? = 2
let c = a ?? b ?? 3 //c Int 1
print(c)
}
}
??与if let的配合使用
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let a: Int? = nil
let b: Int? = 2
if let c = a ?? b {
print(c)
}
//等价于if(a != nil || b != nil)
if let c = a,let d = b {
print(c)
print(d)
}
//等价于if(a != nil && b != nil)
}
}
guard
guard 条件 else {
退出当前作用域
}
- 当前guard条件为false时,就会执行大括号中的代码;
- 当前guard条件为true时,就会跳过大括号中的代码;
- guard语句与if条件语句,功能相反;
- 当使用guard语句进行可选项绑定时,绑定的常量,变量也能在外层作用域中使用;
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
login(["userName":"liyanyan","password":"123456"])
}
func login(_ info: [String : String]) -> Void {
guard let userName = info["userName"] else {
print("请输入用户名")
return
}
guard let password = info["password"] else {
print("请输入密码")
return
}
print("userName = \(userName) -- password = \(password)")
}
}
- guard语句特别适合用来做
提前退出
,即条件不成立的逻辑;
隐式解包
- 在某些情况下,可选项一旦被设定值之后,就一定会拥有值;
- 在这种情况下,可以去掉检查,也不必每次访问的时候都进行解包,因为它能确定每次访问的时候都有值;
- 可以在类型的后面加一个感叹号
!
,定义一个隐式解包的可选项;
let num: Int! = 10
- num是可选项类型,但已经隐式解包了,在使用的时候不用再强制解包;
字符串插值
- 可选项在字符串插值或直接打印的时候,编译器会发出警告;
override func viewDidLoad() {
super.viewDidLoad()
let a: Int? = 10
print(a)
print("a = \(a)")
}
- Expression implicitly coerced from 'Int?' to 'Any'
- String interpolation produces a debug description for an optional value; did you mean to make this explicit?
- 消除警告
override func viewDidLoad() {
super.viewDidLoad()
let a: Int? = 10
print(a!)
print("a = \(a!)")
}
override func viewDidLoad() {
super.viewDidLoad()
let a: Int? = 10
print(a!)
print("a = \(a!)")
print("a = \(String(describing: a))")
}
override func viewDidLoad() {
super.viewDidLoad()
let a: Int? = 10
print(a!)
print("a = \(a!)")
print("a = \(String(describing: a))")
print("a = \(a ?? 0)")
}
多重可选项
override func viewDidLoad() {
super.viewDidLoad()
let num: Int? = 10
let num1: Int?? = num
let num2: Int?? = 10
}
- 可选项num类型为Int?,盒子内部包装了数据10;
- 可选项num1类型为Int??,盒子内部包装了数据Int?,层层包装;
- 可选项num2与num1等价;
override func viewDidLoad() {
super.viewDidLoad()
let num: Int? = nil
let num1: Int?? = num
let num2: Int?? = nil
(num1 ?? 1) ?? 2 //2
(num2 ?? 1) ?? 2 //1
}
- num1与num2不是等价的,这与前面的有所不同;
- 可以通过LLDB指令
fr v -R 可选项
查看数据结构;
案例应用
import Foundation
extension String {
func dateFormatterWithDateString(dateString: String?) -> String {
guard let m_dateString = dateString else { return "" }
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:SS"
dateFormatter.timeZone = TimeZone.current
let date = dateFormatter.date(from: m_dateString)
//date是可选项类型 使用时:
//可直接使用可选项
//也可解包
// 1.强制解包
// 2.可选项绑定 解包
//可强制解包 不推荐若seconds为nil时,会造成runtime崩溃
if seconds! < 0.0 {
}
//可选项绑定 解包
guard let s = seconds,s < 0.0 else { return "" }
return "sss"
}
}
- date在使用时可以
直接使用可选项
,date?
,那么与其相关联的seconds
也是一个可选项 let seconds = date.timeIntervalSinceNow
,seconds在参与运算时必须解包,可强制解包
或 可选项绑定解包
import Foundation
extension String {
func dateFormatterWithDateString(dateString: String?) -> String {
guard let m_dateString = dateString else { return "" }
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:SS"
dateFormatter.timeZone = TimeZone.current
let date = dateFormatter.date(from: m_dateString)
//date是可选项类型 使用时:
//可直接使用可选项
//也可解包
// 1.强制解包
// 2.可选项绑定 解包
let seconds = date!.timeIntervalSinceNow
print(seconds + 10)
//会报错
if let ss = seconds {
print(seconds + 10)
}
return "sss"
}
}
-
let seconds = date!.timeIntervalSinceNow
,date强制解包了,那么seconds就是确定的值,所以直接使用即可,无需解包,解包会报错;