Sometimes you have a struct/class that holds some kind of sequence and you would like to iterate over it with for ... in .... In Swift the struct/class has to conform to SequenceType to enable this iteration.

Let’s say you have a simple struct to hold domains:

struct Domains {
  let names: [String]
  let tld: String
}

To conform to SequenceType the struct needs to implement the method:

func generate() -> Self.Generator

and the Generator is of type GeneratorType. Ok, let’s start with the generator.

The protocol GeneratorType looks like this:

protocol GeneratorType {
  /// The type of element generated by `self`.
  typealias Element
  
  /// Advance to the next element and return it, or `nil` if no next
  /// element exists.
  mutating func next() -> Self.Element?
}

So, the generator need to implement a method next() that returns the next element until no element is left.

A simple generator for the Domains struct could look like this:

struct DomainsGenerator : GeneratorType {
    
  var domains: Domains
  var index = 0
    
  init(domains: Domains) {
    self.domains = domains
  }
    
  mutating func next() -> String? {
    return index < domains.names.count ? "\(domains.names[index++]).\(domains.tld)" : nil
  }
}

The method is mutating because it changes the index property.

The Domains struct would then conform to SequenceType like this:

func generate() -> DomainsGenerator {
  return DomainsGenerator(domains: self)
}

The complete example looks like this:

struct Domains {
  let names: [String]
  let tld: String
}

extension Domains : SequenceType {
  func generate() -> DomainsGenerator {
    return DomainsGenerator(domains: self)
  }
  
  struct DomainsGenerator : GeneratorType {
    
    var domains: Domains
    var index = 0
    
    init(domains: Domains) {
      self.domains = domains
    }
    
    mutating func next() -> String? {
      return index < domains.names.count ? "(domains.names[index++]).(domains.tld)" : nil
    }
  }
}

let domains = Domains(names: ["swiftandpainless","duckduckgo","apple","github"], tld: "com")

for domain in domains {
  print(domain)
}