Swift开发小技巧系列 - 改造Optional

很多开发语言对nil这个概念,也都有不同的处理。Swift也一样,但处理方式有所不同。Swift语言很巧妙创造一种新的类型:Optional, 来修饰可以被赋值nil的变量。有了Optional,可以确保明确处理nil值,让你的程序更加安全。

什么是Optional?

我们先来看看源码

1
2
3
4
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
case none
case some(Wrapped)
}

从上面,我们可以看到,Optional是一种枚举类型。并且一种有关联值(Associated Value)枚举。

如何使用Optional?

当我们定义变量时,其实我们只有两种选择,一种是optional类型的,另一种是non-optional的。这两种具体有什么区别,我们看下面代码。

1
2
3
4
5
6
7
// non-optional
var message: String = "Hello, World!" // 编译正常
message = nil // 编译出错

// optional
var name: String? = "Derek" // 编译正常
name = nil // 编译正常

从上面代码我们可以看出,non-optional类型的变量时不能被赋值nil的。String是non-optional类型,String?是optional类型,它们是两种不同的类型,String是表示字符串类型,String?本质上是枚举类型,只是这个枚举类型的关联值类型为StringSwift语言设计为了安全性,需要你在声明变量时,明确这个变量是否是Optional类型。Swift编译器会以此为依据,在编译期间做相应的检查。

改造Optional

在对Optional类型有了基本了解以后,我们来更进一步。来看看实际开发中,有哪些使用场景需要我们改造下Optional,来让写程序变得更简单些。

场景一:获取UITextField里面的text,并判断是否为nilempty

一般我们会这么写:

1
2
3
4
5
6
guard let text = textField.text, !text.isEmpty else {
// handle for nil or empty
return
}

// Do something with text

因为UITextField的text属性的类型为String?,所有每次都要先解包(unwrap),再检查是否为空。需要两步,我们有没有办法一步解决呢?看下面代码

1
2
3
4
5
6
extension Optional where Wrapped == String {
public var nilIfEmpty: String? {
guard let value = self else { return nil }
return value.isEmpty ? nil : value
}
}
1
2
3
4
5
6
guard let text = textField.text.nilIfEmpty else {
// handle for nil or empty
return
}

// Do something with text

其实我们的目的就是把nilempty当做同一种情况处理。这时候我们可以通过给Optional加一个计算属性nilIfEmpty,当Optional的值为nil或者empty时,这个属性都会返回nil。这样我们每次的处理代码,就只要使用一次解包(unwrap)操作就行了

场景二: 把let names = ["Derek", "", "John", "", "Tony", nil] 里面名字为nilempty的过滤掉

这个需求使用我们自定义的nilIfEmpty,实现起来非常简单,请看下面代码

1
2
3
4
5
6
7
let names = ["Derek", "", "John", "", "Tony", nil]   // [String?]

let validNames1 = names.map { $0.nilIfEmpty } // [String?]
print(validNames1) // [Optional("Derek"), nil, Optional("John"), nil, Optional("Tony"), nil]

let validNames2 = names.flatMap { $0.nilIfEmpty } // [String]
print(validNames2) // ["Derek", "John", "Tony"]

参考资料

联系方式

备注

我们在软件开发的过程中,为了提高效率,其中很重要的一环就是把反复使用到的功能或模块封装起来。因此我在GitHub上开源了一个小工具集 - SwiftDevHints,来总结自己在实际项目开发过程中封装的一些小功能。

刚刚介绍的只是其中一个小功能,想看看其它更多功能,请直接点击SwiftDevHints。如果您觉得对您有所帮助,请给一个star吧。