swift

浅谈 Swift 中的解包操作

2021-06-15  本文已影响0人  QiShare

在 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)

! 的使用场景:

  1. 强制对 可选选类变量 进行解包;
  2. 声明 隐式解包的可选类型变量 的时候, 一般用于类中的属性。

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

上一篇 下一篇

猜你喜欢

热点阅读