Swift可选链
背景
写过swift的同学都只有一个可选链的概念,当我们想访问某个变量的属性或者方法但是不知道到这个变量是否为空的时候,直接使用'.'运算符访问属性或者方法的话,在运行时如果变量是nil则会崩溃,这时一个便捷的方法就是在变量后使用‘?.’的方式来访问。今天就是和大家一个看下这个在swift和OC混用时候的一些问题
基础
可选类型
首先来个小知识点:大家定义可选属性的时候会使用
var name: String?
那么可选类型还能怎么写呢?大家使用过这样的方式吗?
var name: Optional<String>
这第二种方式就是标准库中定义的命名型类型 Optional<Wrapped> 也就是可选类型。而第一种方式只是它的语法糖。
类型 Optional<Wrapped> 是一个枚举,有两个成员,none 和 some(Wrapped),用来表示可能有也可能没有的值。任意类型都可以被显式地声明(或隐式地转换)为可选类型。如果你在声明可选变量或属性的时候没有提供初始值,它的值则会自动赋为默认值 nil。(有关不透明类型请参阅相关paper)
可选链
可选调用就是我们在某个可选值可能为空的基础上去访问它的属性或者方法的操作,而将多个可选调用组合起来就是可选链。
如果可选链中有一个调用失败了,那么整体返回的就是nill,而全部成功的话,不论这个调用的属性、方法返回的值是不是可选值,它的返回结果都是一个可选值。
var name: String? = personA?.info?.name;
案例
先看这么一个问题,假设我们有一个OC的类定义:
@interface ClassA : NSObject
@property (nonatomic, strong) NSArray<person*> *people;
@end
当我们有一个ClassA实例的时候,假设其people是一个nill值,那么我们在swift中这么判断时:
guard instanceA?.people.count ?? 0 else {
return
}
会有什么问题?当我们运行的时候会发生什么呢?
系统会提示如下错误
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
这是因为OC中默认的可以为nil的值在swift中就会变成nil,尽管它声明时处于非空假设中。
而可选链在每个环节都应该加‘?.’。或者说只有加了‘?.’的表达式才称为一个可选链的一部分。
如果我们访问一个包含可选链的判断语句的时候,只有可选链中的部分才会进行为nil就返回的逻辑,比如上述代码中第一部分
instanceA?.
这一部分的意思是如果instanceA为nil则表达式返回nil.反之则返回‘.’运算符的结果对应的可选值。
假设我们的第二个属性也是空的,也就是people为nil;
instanceA?.people
代码到这里也不会有问题,因为‘.’在非空的实例上访问了一个nill值,返回的是一个nil,从而表达式整体都是一个nil的值了。也就是'''instanceA?.people '''表达式的整体值为nil。
但是,当我们加上第三部分的时候, 也就是表达式变成:
instanceA?.people.count
这时people为nil意味着对一个nil的变量做一个属性访问,因为没有'?',相当于强制解包,所以才会出现这个问题。
而至于之后的?? 它计算左表达式的时候就已经崩溃了,所以没有机会执行了。
问题
那么为什么当时写的时候没有加‘?.’而是直接用了‘.’呢。因为定义在OC中,而判断在swift中,OC定义的文件默认会有非空的宏包裹定义。swift默认它时非空的,所以才会出现此问题。
总结
可选链就是多个可选调用的组合,要在每一个可能为空的表达式处加上可选调用'?'才能保证不会对nil值使用‘.’运算符。