可选值
4.1哨岗值 Sentinel Value
定义:有的函数可能返回nil 当函数返回nil 我们将返回值 用作-1 等类似的值代替,这样的值就被称为"哨岗值" 也叫魔法数。
4.2通过枚举来解决魔法数的问题
swift中Optional的本质是一个枚举(目前可以先不具体思考,等以后的项目中慢慢就领悟到了)。
enum Optional<Wrapped> {
case none //为空
case some(wrapped) // 有值
}
知识点:当返回值为可选值 ? 时,实质上返回的是一个Optional的枚举
///返回值为Optional的实质
let strArray = ["one","two","three"]
switch strArray.index(of: "four") {
case .none:
print("返回值为空") //返回值为空
case .some(let idx):
print(idx)
print("有值")
}
4.3可选值概览:Optional
if let
相信大家在swift 入门的时候就已经能很好的使用这个语法了。 不赘述。
技巧1: 可与Bool
联合判断
if let obj = Optional , Bool {
/// 前面有值且后面Bool为true执行
}
技巧2: 多let 并列
。 这个在开发中也经常用到
if let obj1 = Optional1, let obj2 = Optional2, ....{
///当上面的let判断都有值的时候执行
}
while let
类似于if let 遇到nil时终止循环
也有和上面👆技巧1(一旦为false 就循环停止,并不是filter那样去工作
)相同的使用方法。不赘述。
while let line = printLine() {
///当printLine为空时候终止循环
print(line)
}
双重可选值:
一个可选值可能会被另外一个可选值包装起来,形成了可选值的嵌套。你也可以理解成obj?? 。平时在复杂逻辑操作时注意一哈就可以了。
if var 和 while var
和 let 的使用类似。 但你var 出来的obj实际上是一个本地副本
你对obj做任何更改都不会影响
原来的值。
///if var 的改变不影响原值
let dict:[String:String]?
dict = ["key1":"value1"]
if var varDict = dict {
varDict["key1"] = "value2"
}
print(dict) //Optional(["key1": "value1"])
解包后可选值的作用域
if let obj = Optional {
///obj的作用域
}
注:有时候我们需要提前退出
来避免烦人的if嵌套,这个时候 guard let
的优点马上就体现出来了.
///为空提前退出
guard let obj = Optional else{return}
可选链
OC中对nil发送消息,nothing had happened。 在swift中可以通过可选链(Optional chaining)达到一样的效果
那么问题来了,什么是可选链?
可选链
中的可选是?
,可以把链理解成swift中的点语法,可以在《swift链式编程》一书中对这个有更深的理解
delegate?.callback() //就是一个可选链。
//当上面的delegate为可选时编译器会发出警告。 确实有值方法会被调用。没有值时候方法不会被调用。
ps. 😂写了这么多年swift的delegate和闭包 直到自己写笔记的时候才发现自己写复杂了(一点swift的优点都没体现出来。。。)
var voidCallback:(()-> Void)?
///对于闭包调用的两种写法
//❌不推荐
if voidCallback != nil {
voidCallback!()
}
//✅ 推荐
voidCallvack?()
多个可选链的调用。下面这个例子简单易懂,不赘述。
extension Int {
var half: Int? {
guard self > 1 else {return nil}
return self/2
}
}
///多可选链调用
20.half?.half?.half //Optional(2)
nil合并运算符 ?? (项目中经常会用到!!可以让你的代码写的很优美~)
一开始看到标题nil合并运算符
的时候我是😳的。这都是啥啥啥啊。 当我看到 ??
这个符号时候豁然开朗。两个是一个意思 项目里面已经用过很多次了,百试不爽。
使用场景
: 当去解包!
一个可选值,且当这个可选值为nil时,我们要去赋一个默认值
防止崩溃 这个时候就用到了 ??
var number: Int?
number = nil
String(number ?? 5) //5
感觉上是和OC 中的 三目运算符 Bool ? A: B 类似
需要强调的是可选值不是指针
可选值map
可选值flatMap(Demo值得借鉴)
上面两小节讲的都是map 和flatMap对于可选值的一个用法。
有一个小demo对于日常开发可以说是有着四两拨千斤
的感觉,如下:
///将一个网络图片加载出来的奇淫方法!!!
let urlString = "http://www.objc.io/logo.png"
let view = URL(string: urlString)
.flatMap { (url) -> Data? in
try? Data(contentsOf: url)
}
.flatMap { (data) -> UIImage? in
UIImage(data: data)
}
.map { (image) -> UIImageView in
UIImageView(image: image)
}
if let view = view {
UIView().addSubview(view)
}
利用swift中的$0
语法简化上面的代码
let view2 = URL(string: urlString)
.flatMap {
try? Data(contentsOf: $0)
}
.flatMap {
UIImage(data: $0)
}
.map {
UIImageView(image: $0)
}
if let view2 = view2 {
UIView().addSubview(view2)
}
这里的flatMap
和if let
非常相似。
这样我们就将一个网络图片加载出来了。
想想自己之前写了那么多的垃圾代码,不禁长叹一句:swift🐂🍺!!!
使用flatMap过滤nil
同样这里我们用一个demo去说明用法
目的
:我们想要求一个字符串数组中的数字和。
let numbers = ["1","2","3","4","liaoworking"]
///普通青年
var sum = 0
for case let i? in numbers.map({
Int($0)
}) {
sum += i// Int($0)为nil就不走这里了
}
// sum的值为10
///优质青年
///当我们用?? 把nil替换成0
numbers.map { Int($0) }.reduce(0) { $0 + ($1 ?? 0)} //10
///文艺青年
///在标准库中flatMap的作用可能正是你想要
numbers.flatMap { Int($0) }.reduce(0, +) // 10
注:这里的flatMap的作用:把一个映射为可选值的序列进行展平。
这个例子的确好吊,不自己写一遍不知道还有很多高级用法自己不会。
学习了学习了~
如果让我去面试swift开发。一定会选这个demo做一个面试题!
可选值判等
判等时我们并不关心可选值是不是nil,只用去管它是否包含
我们想要的非nil的特定值
即可。
switch case 匹配可选值
/// switch case
let numbers = ["1","2","3","4","liaoworking"]
for i in numbers {
switch Int(i) {
case 0:
print("0")
case nil:
print("can't convert to int")
default:
print("not in case")
}
}
swift中case匹配是通过~=运算符进行的。 我们可以实现这个方法增加对范围
(0..<num)匹配的方法
可选值的比较
和 == 类似 可选值曾经也有 <=, >=, <, >操作符 后来在SE-0121因为安全原因
被移除了。
///在一个温度数组中
let temp = ["-23", "0", "66.66", "warm"]
Double("warm") 的值为nil
Double("warm") < 0 是成立的
但你不能说warm是小于0度的是很冷的。
这显然不合情理。