OC vs Swift -- Optional

2017-03-27  本文已影响207人  JellyL

Why Optional#

引入optional可以解决两个问题,

  1. 解决潜在crash问题
[dict setObject: objc forKey: @“someKey"];

比如OC中像集合dict的someKey设置值为objc, 当objc为nil时,程序运行到这句代码时会crash,利用 optional 的机制更严格的类型检查,使得在编译时可以发现更多问题,把这种潜在的错误及时的排除掉了;

  1. 解决空类型不详的问题,“无”和“空”划分得更清晰,表述更明确, 让代码可读性更高。

定义#

Optional定义

OC和Swift中通过不同的修饰符来表示optional变量,由于swift有语法糖的支持,所以OC相对于Swift来说语法上略显得啰嗦了一些。但是在OC中为了防止写一大堆 nonnull,Foundation 还提供了一对宏,包在里面的对象默认加 nonnull 修饰符,只需要把 nullable 的指出来就行。

#import "Ship.h"

NS_ASSUME_NONNULL_BEGIN
@interface ShipList : NSObject

- (nullable Ship*)shipWithName: (NSString *)name;
- (NSInteger)indexOfShip: (Ship *)ship;

@property (copy, nullable) NSString *name;
@property (copy, readonly) NSArray *allShips;

@end
NS_ASSUME_NONNULL_END

其实OC中并没有真正支持optional, 只是编译器帮忙做了检查,会对错误提出警告,但是程序依然可以通过编译,在运行时会crash。


OC-Optional.png

而相同的代码用Swift实现,编译器在编译过程中就会报错。


Swift-Optional-Check.png

Swift中的Optional是由ENUM + 范型定义的一个数据类型; Optional.none 是空的字面量,Optional.some(Wrapped) 存储了一个包裹的值。引入Optional封装nil,nil有类型后,才能融入强类型语言范畴。


Optional.png

这个被包裹的值就好像礼物盒子里的礼物一样,你只有把盒子打开才知道里面的东西到底是什么。

struct Gift {
    let sender: String = "June"
    let name: String = "💄"
}

func whatIsTheGift(giftBox: Gift?) {
    if let gift = giftBox {
        print("the giftis \(gift.name)")
    } else {
        print("there is no gift")
    }
}

var 🎁: Gift?
whatIsTheGift(🎁)
// there is no gift

🎁 = Gift()
whatIsTheGift(🎁)
// the gift is 💄

而打开礼物这个过程我们通常称为unwrapp(解包或者拆包),Swift有以下几种方式进行解包:

* !  (直接解包,快速,短小精悍, 但如果沒值会直接crash,使用的时候一定要保证optional变量有值)
* if / switch (可以避免沒有值还硬拆的狀況,也可以处理沒有值的情况)
* if let / guard let  (可以从第三方拆完直接拿到值,不用自已拆)
* ??  (空合运算符,当optional变量为 nil 时,直接提供符合逻辑的初始值,但是可能引起难以定位到错误原因的问题,慎用)

举个🌰,一个optional变量 name,当值为June时,5种方式进行解包都可以,打印结果一致。

Optional-unwrap-example-one
但是当optional变量 name值为nil时, 直接解包的方式会crash掉。而空合运算符解包的方式打印结果与其他三种并不相同。
optional-unwrapp-exaple-two

所以总体来说应该首选if let / guard let, 最不建议直接使用!,而?? 根据使用场景来选择,慎用。

上一篇下一篇

猜你喜欢

热点阅读