
一. 引言
很多开发者第一次接触迭代器模式时都会有一个疑问:为什么在实际开发中几乎没有写过迭代器?
但其实,在日常 iOS 开发中,我们几乎每天都会遍历数组、字典或者集合。例如:
Swift
for item in array {
print(item)
}
或者:
Swift
array.forEach { item in
print(item)
}
这些写法已经非常自然,以至于我们很少会思考:这些遍历背后的实现机制是什么?
事实上,这正是经典设计模式中的 迭代器模式(Iterator Pattern)。
不过在现代 Swift 开发中,我们很少需要自己实现迭代器,因为 Swift 标准库已经把这一模式内置到了语言层面。但理解它依然很有价值,因为很多系统 API 和高级集合操作都是基于这一模式实现的。
本文我们就来一起看看 什么是迭代器模式,以及它在 iOS 开发中的实际应用方式。
二. 什么是迭代器
迭代器模式的核心思想是:在不暴露集合内部结构的情况下,顺序访问集合中的元素。
换句话说:
- 集合负责存储数据
- 迭代器负责遍历数据
调用者只需要关心下一个元素是谁。而不需要关心集合内部到底是数组、链表还是树。
这就实现了 访问逻辑与数据结构的解耦。
三. 传统迭代器模式
在经典设计模式中,迭代器通常包含以下几个角色:
Iterator(迭代器接口)
负责定义遍历方法,例如:
Swift
next()
hasNext()
ConcreteIterator(具体迭代器)
真正实现遍历逻辑。
Aggregate(集合接口)
定义创建迭代器的方法。
ConcreteAggregate(具体集合)
具体的数据存储结构。
Swift
Aggregate
│
└── createIterator()
Iterator
├── next()
└── hasNext()
调用者通过迭代器来访问集合,而不是直接访问集合内部数据。
四. Swift 中的迭代器
在 Swift 中,这一模式已经被标准库封装为两个核心协议:
Swift
Sequence
IteratorProtocol
IteratorProtocol
定义了最核心的方法:
Swift
protocol IteratorProtocol {
associatedtype Element
mutating func next() -> Element?
}
next() 每次返回一个元素,当没有元素时返回 nil。
Sequence
Sequence 表示 一个可被遍历的集合。
Swift
protocol Sequence {
associatedtype Iterator: IteratorProtocol
func makeIterator() -> Iterator
}
当一个类型遵守 Sequence 时,就可以被 for-in 遍历。
例如:
Swift
let array = [1,2,3]
var iterator = array.makeIterator()
while let value = iterator.next() {
print(value)
}
而我们平时写的:
Swift
for value in array {
print(value)
}
五. 实现一个自定义迭代器
接下来我们实现一个简单的例子:一副扑克牌 Deck。
目标是让它支持这样的遍历方式:
Swift
for card in deck {
print(card)
}
5.1 定义 Card 和 Deck
Swift
struct Card {
let suit: String
let number: Int
}
class CardDeck {
private var cards: [Card] = []
init() {
let suits = ["♠️","♥️","♣️","♦️"]
for suit in suits {
for number in 1...13 {
cards.append(Card(suit: suit, number: number))
}
}
}
}
这里我们创建了一副标准的 52 张牌。
5.2 创建 DeckIterator
Swift
struct CardDeckIterator: IteratorProtocol {
private var cards: [Card]
private var index = 0
init(cards: [Card]) {
self.cards = cards
}
mutating func next() -> Card? {
guard index < cards.count else {
return nil
}
let card = cards[index]
index += 1
return card
}
}
这个迭代器负责:
- 记录当前位置 index
- 每次返回一张牌
- 遍历结束返回 nil
5.3 让 Deck 支持遍历
接下来让 CardDeck 遵守 Sequence:
Swift
extension CardDeck: Sequence {
func makeIterator() -> CardDeckIterator {
return CardDeckIterator(cards: cards)
}
}
现在就可以这样使用了:
Swift
let deck = CardDeck()
for card in deck {
print(card)
}
六. 关于自己实现迭代器
但其实在客户端开发中,我们确实很少自己来写迭代器。主要是Swift的标准库就已经实现了,我们常用的集合类型:
Swift
Array
Set
Dictionary
全部已经遵守 Sequence,因此我们天然就拥有了遍历能力。
除了我们常用的遍历函数,Swift还提供了很多基于迭代器的高级函数:
Swift
map
filter
reduce
compactMap
forEach
我们使用起来又方便,又快捷。
另外就是通常在在客户端需要处理的业务数据结构都很简单,大多数APP中,我们就只需要使用 Array或者Dictionary就够了。很少会自己来实现复杂的集合结构,因此也就很少需要手写迭代器。
七. 结语
迭代器模式是一个非常经典的设计模式,它解决的问题其实非常简单:如何在不暴露内部结构的情况下遍历集合。
在现代 Swift 开发中,我们很少需要自己实现迭代器,因为Sequence,IteratorProtocol 已经把这一模式内置到了语言层面。
但理解它依然非常重要。