Um "iterador" é um dos padrões de design que os programadores geralmente não percebem, porque sua implementação, como regra, é embutida diretamente nas ferramentas padrão da linguagem de programação. No entanto, esse também é um dos padrões comportamentais descritos no 
livro “Gang of Four”, “GoF”, “Design Patterns: Elementos de Software Orientado a Objetos Reutilizáveis” e compreende seu dispositivo nunca dói, e às vezes pode até ajudar em algo.
Um "iterador" é um método de acesso seqüencial a todos os elementos de um objeto composto (em particular, tipos de contêiner, como uma matriz ou conjunto).Ferramentas de linguagem padrão
Crie algum tipo de 
matriz :
let numbersArray = [0, 1, 2] 
... e depois "caminhe" por um 
ciclo :
 for number in numbersArray { print(number) } 
... parece uma ação muito natural, especialmente para linguagens de programação modernas como 
Swift . No entanto, nos bastidores dessa ação simples, há um código que implementa os princípios do padrão Iterator.
Em "Swift", para poder "iterar" uma variável usando 
for , o tipo de variável deve implementar 
o protocolo Sequence . Entre outras coisas, esse protocolo exige que o tipo tenha um 
Iterator tipo 
associatedtype , que por sua vez deve implementar os requisitos do protocolo 
IteratorProtocol , bem como o 
método de fábrica makeIterator() , que retorna um "iterador" específico para este tipo:
 protocol Sequence { associatedtype Iterator : IteratorProtocol func makeIterator() -> Self.Iterator  
O protocolo 
IteratorProtocol , por sua vez, contém apenas um método - 
next() , que retorna o próximo elemento na sequência:
 protocol IteratorProtocol { associatedtype Element mutating func next() -> Self.Element? } 
Parece "muito código complicado", mas na verdade não é. Abaixo veremos isso.
O tipo 
Array implementa o protocolo 
Sequence (embora não diretamente, mas através da cadeia de 
herança do 
protocolo : o 
MutableCollection herda os requisitos de 
Collection e o último herda os requisitos de 
Sequence ), para que suas instâncias, em particular, possam ser "iteradas" usando 
for -cycles.
Tipos personalizados
O que precisa ser feito para poder iterar seu próprio tipo? Como costuma acontecer, é mais fácil mostrar um exemplo.
Suponha que haja um tipo representando uma estante de livros que armazena um determinado conjunto de instâncias de uma classe, que por sua vez representa um livro:
 struct Book { let author: String let title: String } struct Shelf { var books: [Book] } 
Para poder "iterar" uma instância da classe 
Shelf , essa classe deve atender aos requisitos do protocolo 
Sequence . Neste exemplo, basta implementar o método 
makeIterator() , principalmente porque os outros requisitos de protocolo têm 
implementações padrão . Este método deve retornar uma instância de um tipo que implementa o protocolo 
IteratorProtocol . Felizmente, no caso do Swift, esse código é muito pouco, muito simples:
 struct ShelfIterator: IteratorProtocol { private var books: [Book] init(books: [Book]) { self.books = books } mutating func next() -> Book? {  
O método 
next() do tipo 
ShelfIterator declarado 
mutating , porque a instância do tipo deve de alguma forma armazenar o estado correspondente à iteração atual:
 mutating func next() -> Book? { defer { if !books.isEmpty { books.removeFirst() } } return books.first } 
Esta opção de implementação sempre retorna o primeiro elemento da sequência ou 
nil se a sequência estiver vazia. O bloco de 
defer "empacotado" com o código para alterar a coleção iterada, que remove o elemento da última etapa da iteração imediatamente após o retorno do método.
Exemplo de uso:
 let book1 = Book(author: ". ", title: "") let book2 = Book(author: ". ", title: " ") let book3 = Book(author: ". ", title: " ") let shelf = Shelf(books: [book1, book2, book3]) for book in shelf { print("\(book.author) – \(book.title)") }  
Porque todos os tipos usados (incluindo a 
Array subjacente à 
Shelf ) são baseados na 
semântica dos valores (em oposição às referências) , não é necessário se preocupar com o valor da variável original sendo alterada durante a iteração. Ao manipular tipos com base na semântica de links, esse ponto deve ser lembrado e levado em consideração ao criar seus próprios iteradores.
Funcionalidade clássica
O “iterador” clássico descrito no livro “Gangs of Four”, além de retornar o próximo elemento da sequência iterável, também pode a qualquer momento retornar o elemento atual no processo de iteração, o primeiro elemento da sequência iterável e o valor da “flag” indicando se ainda há elementos em uma sequência iterada em relação à etapa de iteração atual.
Obviamente, seria fácil declarar um protocolo, expandindo assim os recursos do 
IteratorProtocol padrão:
 protocol ClassicIteratorProtocol: IteratorProtocol { var currentItem: Element? { get } var first: Element? { get } var isDone: Bool { get } } 
Os elementos primeiro e atual são retornados opcionais, pois a sequência de origem pode estar vazia.
Opção de implementação simples:
 struct ShelfIterator: ClassicIteratorProtocol { var currentItem: Book? = nil var first: Book? var isDone: Bool = false private var books: [Book] init(books: [Book]) { self.books = books first = books.first currentItem = books.first } mutating func next() -> Book? { currentItem = books.first books.removeFirst() isDone = books.isEmpty return books.first } } 
Na descrição original do padrão, o método 
next() altera o estado interno do iterador para ir para o próximo elemento e é do tipo 
Void , e o elemento atual é retornado pelo método 
currentElement() . No protocolo 
IteratorProtocol , essas duas funções são como se combinadas em uma.
A necessidade do 
first() método 
first() também é duvidosa, porque o iterador não altera a sequência original e sempre temos a oportunidade de acessar seu primeiro elemento (se houver, é claro).
E, como o método 
next() retorna 
nil quando a iteração é concluída, o método 
isDone() também se torna inútil.
No entanto, para fins acadêmicos, é bem possível criar uma função que possa usar toda a funcionalidade:
 func printShelf(with iterator: inout ShelfIterator) { var bookIndex = 0 while !iterator.isDone { bookIndex += 1 print("\(bookIndex). \(iterator.currentItem!.author) – \(iterator.currentItem!.title)") _ = iterator.next() } } var iterator = ShelfIterator(books: shelf.books) printShelf(with: &iterator)  
O parâmetro 
iterator é declarado 
inout porque seu estado interno muda durante a execução da função. E quando a função é chamada, a instância do iterador é transmitida não diretamente por seu próprio valor, mas por referência.
O resultado da chamada do método 
next() não é usado, simulando a ausência do valor de retorno de uma implementação de livro didático.
Em vez de uma conclusão
Isso parece ser tudo que eu queria dizer dessa vez. Todo o código bonito e deliberado escrevê-lo!
Meus outros artigos sobre padrões de design: