阅读 305

Swift 可选类型使用及设计思路推测, ?、!、 ??等的用法

在可选类型之前,我们有个概念要搞清楚,类型安全。 什么是类型安全呢? 从字面上理解,就是这个类型是安全的,即这个类型不可以被赋予其他类型的值。 比如一个string类型的变量,不可以被赋值一个int值。 OC是不是类型安全呢? 不是的,比如很多对象都可以被赋予nil,这就属于赋予其他类型。

在OC中,如果想要判断某个值是否含有有效值,我们通常会使用nil来判断,但是nil的作用范围仅限于大部分对象,对于struct等类型,还需要判断是否NSNotFound等

基于此,Swift语法中进行了改良,提供了可选类型,可选类型更像是一个集合,表明这个类的实例属于{该类, nil} 中的一种。上述提到Swift是类型安全的语言,一个对象,要么是属于一个类,要么是属于nil,我们无法将nil赋值给一个Int类型的对象,但是可以将nil赋值给一个Optional Int对象

这里的源码也证明了我们的推测,Optional是一个enum合集

//   swift/stdlib/public/core/Optional.swift
public enum Optional : ExpressibleByNilLiteral {
    case none   //要么是none
    case some(Wrapped) //要么是某个类
    
    public init(_ some: Wrapped)
    public func map(_ transform: (Wrapped) throws -> U) rethrows -> U?
    public func flatMap(_ transform: (Wrapped) throws -> U?) rethrows -> U?
    public init(nilLiteral: ())
    public var unsafelyUnwrapped: Wrapped { get }
}
复制代码

nil赋值给可选类型

var code = 4
code = nil //error  'nil' cannot be assigned to type 'Int'

var code: Int? = 4
code = nil
复制代码

另外要特别注意:在OC中,nil标志这个对象指向了一个不存在的对象,而在swift中,nil表明这个对象缺失有效的值。 我非常理解Swift为了兼容OC仍然使用了nil这个关键词,但是我觉得用JS中的Undefined会更通俗易懂。

强制解析(可选类型赋值给不可选类型)

在swift中,直接将可选类型赋值给非可选类型是会报错的。 如果我们确认可选类型有值,则可以强制解析来赋值,强制解析直接在可选类型的实例后面增加!即可

let string1: String? = "abc"
let string2: String = string1 //error Value of optional type 'String?' must be unwrapped to a value of type 'String'

let string1: String? = "abc"
let string2: String = string1! //correct
复制代码

虽然第二种写法已经编译成功,但是因为这种做法可能会导致运行时崩溃,所以swift的官方文档还是推荐先进行判断再来赋值,即:

let string1: String? = "abc"
if string1 != nil { //best practice
  let string2: String = string1!
  print(string2)
}
复制代码

可选绑定

在OC中,如果我们希望判断参数不为nil的时候,通常做法是这样的

if (a != nil && b != nil){
    //case
}
复制代码

而有了可选类型,swift中也带来了更优雅的写法

if let a1 = a, let b1 = b { // equal to (a != nil && b != nil)
 
}
复制代码

另外在OC或者JS中判断某个值是否为空时,经常需要判断该类的上层是否有值,否则容易出现崩溃,如

if (person && person.homeInfo && person.homeInfo.adress){

}
复制代码

我们在swift中可以使用可选链调用来解决

let adress = person?.homeInfo?.adress {
}
复制代码

隐式解析可选类型

如果我们知道一个可选类型实际是有值的,那么一直判断nil然后再赋值的做法就有些冗余了,swift也带来了隐式解析,大白话讲就是: 虽然你声明成了一个可选类型,但是我知道你其实是有值的,所以我将你当成有值的类型来使用

举例:

//正常使用方法
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要感叹号来获取值
 
 //隐式解析
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感叹号
复制代码

其他语法糖

在ES6中,提供了如下语法糖,如果对象是undefined,则使用其他默认值 let string = a || 'string value'

而swift也参考了这种做法,不过符号变成了两个问号??

let a = string ?? "string value"
复制代码

为什么swift设计了可选类型

  1. swift是类型安全的语言,需要可选类型来兼容oc并且提供一个缺失值的状态,类似于undefined
  2. 可选类型带来了判断nil的更强大和优雅的写法及语法糖

参考

swiftgg.gitbook.io/swift/swift…

文章分类
iOS
文章标签