A common thing we do when enumerating arrays is to keep track of the current index.

There are various ways to achieve this.

Existing solutions

Sure, you can use a for loop. The usual array length safety issues apply here. We don’t want to go beyond the end of the array and crash. This is not much different from iterating an array in C. We can definitely make something that is easier to read.

let times = array.count
for var i = 0; i < times; i++ {
    let item = array[i]
    println("\(item) is at index \(i)")
}

The next method takes advantage of Swift’s for-in syntax for collections. Keeping track of what index we are at requires the use of a local integer. Each time through the loop we need to make sure to update the index. This is an improvement on the plain for loop, becuase the for-in syntax guarantees that we won’t walk right off the end of our array. The glaring disadvantage is that we must manually update the index each time. And if we have some nested if statements that contain continue, index must be incremented in multiple places.

var index: Int = 0
for item in array {
    println("\(item) is at index \(index)")

    // make sure to update the index
    index++
}

NSArray provides block-based enumeration methods that provide the current item and index. The main disadvantage here is that we are using NSArray instead of a native Swift array. That’s a problem becuase we can’t put Swift structs or enums inside an NSArray.

let arr: NSArray = [1, 2, 3, 4]
arr.enumerateObjectsUsingBlock({ item, index, _ in
    println("\(item) is at index \(index)")
})

Swift Solution

We can add an enumerateWithIndex method to Array via an extension. The method takes a block of type (Element, Int) -> Void. In the context of Array, Element means the kind of object that the array can contain. For an array that contains Ints, Element is Int. We simply enumerate the array from the start index up to the end index, which I’ve extracted into a local variable called fullRange. At each iteration, we call the block with the current item and the current index.

extension Array {

    func enumerateWithIndex(block: (item: Element, index: Int)->Void) {
        let fullRange = startIndex..<endIndex
        for x in fullRange {
            block(item: self[x], index: x)
        }
    }

}

Now it’s a simple method call to enumerate an array, getting back the current object and index.

[1, 2, 3].enumerateWithIndex({ item, index in
    println("\(item) is at index \(index)")
})
// 1 is at index 0
// 2 is at index 1
// 3 is at index 2

["A", "B", "C"].enumerateWithIndex({ item, index in
    println("\(item) is at index \(index)")
})
// A is at index 0
// B is at index 1
// C is at index 2