masters3d masters3d - 2 months ago 10
Swift Question

Any way to iterate a tuple in swift?

I am curious how to do a for loop with a tuple in swift.

I know that to access each member you can use dot notation using the index number

var tupleList = ("A",2.9,3,8,5,6,7,8,9)

for each in tupleList {
println(each)
}


//Error: Type does not conform to protocol sequence

Answer

Yes, you can!

func iterate<C,R>(t:C, block:(String,Any)->R) {
    let mirror = reflect(t)
    for i in 0..<mirror.count {
        block(mirror[i].0, mirror[i].1.value)
    }
}

And voila!

let tuple = ((false, true), 42, 42.195, "42.195km")
iterate(tuple) { println("\($0) => \($1)") }
iterate(tuple.0){ println("\($0) => \($1)")}
iterate(tuple.0.0) { println("\($0) => \($1)")} // no-op

Note the last one is not a tuple so nothing happens (though it is a 1-tuple or "Single" which content can be accessed .0, reflect(it).count is 0).

What's interesting is that iterate() can iterate even other types of collection.

iterate([0,1])              { println("\($0) => \($1)") }
iterate(["zero":0,"one":1]) { println("\($0) => \($1)") }

And that collection includes class and struct!

struct Point { var x = 0.0, y = 0.0 }
class  Rect  { var tl = Point(), br = Point() }
iterate(Point()) { println("\($0) => \($1)") }
iterate(Rect())  { println("\($0) => \($1)") }

Caveat: the value passed as the 2nd argument of the block is type Any. You have to cast it back to the values with original type.