这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战
往期文章: 你可能不知道的 Swift 开发小技巧——Pt.1
对数组进行分组
假如有一组文章,要把这些文章按照 category 进行分组,可以利用 Pt.1中提到的,给字典的某个 key 设置默认值的技巧,实现如下:
struct Article {
let title: String
let category: String
}
let articles = [
Article(title: "标题1", category: "Swift"),
Article(title: "标题2", category: "Swift"),
Article(title: "标题3", category: "Objective-C"),
Article(title: "标题4", category: "Objective-C"),
]
var groupByCategory = [String : [Article]]()
for article in articles {
groupByCategory[article.category, default: []].append(article)
}
print(groupByCategory)
复制代码
实际上我们可以使用 Dictionary 的内置初始化方法来简化上面的 for 循环:
let groupByCategory = Dictionary(grouping: articles, by: {$0.category})
print(groupByCategory)
复制代码
检查所有集合项是否满足条件
假如有这么需求:给定一组表示年龄的整型数组,求他们的平均年龄。计算总和,除以数量,so easy~
然而并不是每个整数都能表示年龄,因为传入的值有可能小于等于 0。对于输入参数:年龄数组,是不可控的。因此遇到不符合实际的值,需要抛出错误。通常会这么实现:
func findAverage(ages: [Int]) -> CGFloat {
var isAgeValid = true
for age in ages {
if age <= 0 {
isAgeValid = false
break
}
}
guard isAgeValid else {
fatalError("所有的年龄必须大于 0")
}
let sum = ages.reduce(0, +)
let count = ages.count
return CGFloat(sum) / CGFloat(count)
}
findAverage(ages: [22, 25, 26, 28, 30])
复制代码
我们可以使用 Array 的方法:allSatisfy(_:)
来简化 for 循环代码:
func findAverage(ages: [Int]) -> Double {
let isAgeValid = ages.allSatisfy { $0 > 0 }
guard isAgeValid else {
fatalError("所有的年龄必须大于 0")
}
let sum = ages.reduce(0, +)
let count = ages.count
return Double(sum) / Double(count)
}
findAverage(ages: [22, 25, 26, 28, 30])
复制代码
保留 Struct 的默认初始化器
大家都知道,Swift 中的 Struct 是值类型,自带一个成员初始化器。
不知道大家有没有遇到这样的情况,需要自定义 Struct 的初始化器,又想保留默认的初始化器,但是自定义后,默认的初始化器就消失了。
先看下默认的初始化器:
自定义初始化器后,默认初始化器就消失了:
想同时保留自定义的和默认的,就得祭出 extension 大法了:
过滤数组中的 nil
提到过滤,第一反应可能就是 filter(_:)
:
let x = [1, nil, 2, 4]
let y = x.filter { $0 != nil }
复制代码
虽然也可以,但不不是那么好。上面的 x 的类型 [Int?],y 也是。有什么问题?问题是,我们已经明确知道 y 里面不会包含 nil 值了,但编译器不知道,所以在遍历 y 时,依然需要对其中的元素进行解包:
let x = [1, nil, 2, 4]
let y = x.filter { $0 != nil }
for item in y {
print("item is \(item!)")
}
复制代码
更好的做法是使用 compactMap(_:)
:
let x = [1, nil, 2, 4]
let y = x.compactMap { $0 }
复制代码
这时候 x 是 [Int?] 的类型,y 是 [Int] 的类型。
zip
假如需要同时遍历两个数组,你会怎么做?在我知道 zip 之前,我通常都是这么做:
let array1 = ["title1", "title2", "title3", "title4"]
let array2 = ["value1", "value2", "value3", "value4", "value5"]
let count = min(array1.count, array2.count)
for i in 0..<count {
let title = array1[i]
let value = array2[i]
}
复制代码
再来看看 zip 的用法,zip 可以组合两个序列,而且会进行边界检查:
for (title,value) in zip(array1, array2) {
print("\(title)---\(value)")
}
//输出结果
title1---value1
title2---value2
title3---value3
title4---value4
复制代码
结语
- 使用 Dictionary 的 init(grouping:by:) 方法对数组进行分组
- 使用 Array 的 allSatisfy(_:) 方法检查所有集合项是否满足条件
- 通过 extension 添加自定义初始化器从而保留默认初始化器
- 使用 compactMap(_:) 过滤数组中的 nil
- 使用 zip 组合两个集合
往期文章: 你可能不知道的 Swift 开发小技巧——Pt.1
以上就是平时在项目中使用比较多的 Swift 小技巧啦,我也会继续总结更多的小技巧和大家进行分享~
如果大家遇到以前没用到过的,不妨动手试试吧~