在 Swift 中我们会接触到可选类型 Optional,刚开始写代码时会被变量后的 ?、!、?? 等符号弄得稀里糊涂。
首先,对于以下代码:
var num: Int?
num = 10
if num is Optional<Int> {
print("它是可选类型")
} else {
print("它是Int类型")
}
在IDE中的if上一定会出现这样一个warning:'is' test is always true。也就是说 num 不是 Int 类型,而是 Optional 类型。
1. Optional类型
可选类型声明,如下:
var num : Int?
// let num2 : Int? // let类型变量只可被初始化一次
以上声明的意思是:声明了一个变量,它的值可能是一个 Int 值,也可能为 nil 。也即,实际上声明的是 Optional 类型的变量,而不是声明了一个 Int 类型的。
正是因为 num 是一个可选类型,所以它才能赋值为 nil ,var num : Int = nil,这样是不可能赋值成功的,因为Int类型中没有 nil 这个概念!在 OC 中对象都可以赋值为 nil ,但在 Swift 中能赋值为 nil 的只有 Optional 类型!
2. 关于解包
解包符号为 !
如果确定一个可选类型的值一定存在,那么我们使用 !进行解包来获取它的值,或者使用 Optional Binding 来处理。
let possiablestring: String? = "An possiable string"
print(possiablestring!) // 强制解包 确定possiablestring的值确实存在,不需要每次都验证它的值 let strValues = possiablestring!.hashValue
也可以把 隐式解包可选类型 当成对每次使用的时候自动解包的可选类型。隐式解包不是每次使用的时候 在变量/常量后面加 !,而是直接在定义的时候加 !。
let assumString: String! = "an optional string"
print(assumString, assumString.hashValue)
! 的使用场景:
- 强制对 可选选类变量 进行解包;
- 声明 隐式解包的可选类型变量 的时候, 一般用于类中的属性。
3. 解包的基本思路
使用 if let 或者 guard let,而非强制解包。对于如下方法:
func getHeight(_ height: Float?) -> Float? {
if height != nil {
return height! / 100
}
return nil
}
以上代码中使用 ! 对height进行强制解包,然后参与运算,其中每使用一次都要进行强制解包。强制解包过程中一旦解包失败,就会引起崩溃,安全的解包行为应该是通过if let 或者guard let,这种被称为可选绑定的操作来处理的:
// if let
func getHeight(_ height: Float?) -> Float? {
if let unwrapedHeight = height {
return unwrapedHeight / 100
}
return nil
}
//// guard let
//func getHeight(_ height: Float?) -> Float? {
// guard let unwrapedHeight = height else {
// return nil
// }
// return unwrapedHeight / 100
//}
注意:
对于 if let ,大括号中是符合条件的正常情况,而外部是非正常情况;
对于 guard let ,guard let else中的大括号是异常情况,而外部返回的是正常情况。
多几个前置 guard let 进行判断,有时可以让代码更具可读性。
4. 可选链的解包
对于以下两个类:
class Person {
var phone: Phone?
}
class Phone {
var number: String?
}
解包时不必一层层进行判断,因为可选链中一旦有某个链为 nil ,那么就会返回 nil ,过程如下:
let dora = Person()
guard let number = dora.phone?.number else {
return
}
5. _Nonnull、nonnull 与 可选类型 的关系
对于拼接字符串方法,OC 中是这样:
- (NSString *)stringByAppendingString:(NSString *)aString;
Swift 中是这样:
public mutating func append(_ other: String)
仅从 API 来看,OC 的入参是很危险的,因为类型是 NSString * ,那么 nil 也可以传入,这样会崩掉,应该写成:
- (NSString *)stringByAppendingString:(NSString * _Nonnull)aString;
//// 或
//- (NSString *)stringByAppendingString:(nonnull NSString *)aString;
这样以便提示程序员,入参不能为空。Swift 则不会出现这种情况,other 后面的类型为String ,而不是 String? ,说明入参是一个非可选类型。
参考文章:
http://www.mamicode.com/info-detail-1160599.html
https://www.jianshu.com/p/4bfbb0ba4d32
网友评论