Swift - Adopting SequenceType
Here’s an example of implementing SequenceType in Swift (1.2).
Here is the existing Objective-C class I’m working with (well, a simplification thereof, written in Swift).
class MyStringCollection: NSObject {
    private let strings: [String]
    init(strings: [String]) {
        self.strings = strings
    }
    func count() -> Int {
        return strings.count
    }
    func stringAtIndex(index: Int) -> String?  {
        return strings[index]
    }
    func indexOfString(string: String) -> Int {
        return find(strings, string) ?? NSNotFound
    }
}
Here is what it looks like to use it:
// Example of using it:
let stringCollection = MyStringCollection(strings: [ "a", "b", "c", "d", ])
stringCollection.count()                    // => 4
stringCollection.stringAtIndex(2)           // => "c"
stringCollection.indexOfString("b")         // => 1
stringCollection.indexOfString("notfound")  // => 9223372036854775807
But, we can’t enumerate it (yet).
for (i, string) in enumerate(stringCollection) {
    println("string \(i): \(string)")        <-- error: Cannot invoke 'enumerate' with an argument list of type '(MyStringCollection)'
}
Enter SequenceType
The error message above wasn’t terribly helpful, but cmd-clicking on
enumerate(), we see that it wants the argument to be SequenceType:
func enumerate<Seq : SequenceType>(base: Seq) -> EnumerateSequence<Seq>
So, let’s make our above class adopt SequenceType.
extension MyStringCollection: SequenceType {
    typealias Generator = MyStringCollectionGenerator
    // This is the requirement of SequenceType
    // It will be called once when we start enumerating, and returns a Generator,
    // which holds state about where we are in the sequence, and can return the
    // next item.
    func generate() -> MyStringCollectionGenerator {
        return MyStringCollectionGenerator(currentIndex: 0, collection: self)
    }
    // Here is the custom generator we return above.
    // It just has a reference to the original collection, and an integer
    // pointing to the current position in that collection.
    struct MyStringCollectionGenerator: GeneratorType {
        typealias Element = String
        var currentIndex: Int
        let collection: MyStringCollection
        // This is the requirement of GeneratorType
        mutating func next() -> Element?  {
            if currentIndex >= collection.count() {
                return nil
            }
            return collection.stringAtIndex(currentIndex++)
        }
    }
}
And, now we can enumerate() it.
for (i, string) in enumerate(stringCollection) {
    println("string \(i): \(string)")
}
Prints out:
string 0: a
string 1: b
string 2: c
string 3: d
Further Reading
- Overview of Swift collection protocols on NSHipster
- Jacob’s great post about implementing the Fibonacci Sequence using SequenceType
Thanks
As usual, thanks to Jacob, for his help with this – both explaining this to me a few months ago at work, and reviewing this post.