This post from Martin R is a good step in the right direction toward generalizing your problem.
The helper function at the top of the post is already what you need for making a more generalized loop:
public func sequence<T>(first: T, while condition: @escaping (T)-> Bool, next: @escaping (T) -> T) -> UnfoldSequence<T, T> {
let nextState = { (state: inout T) -> T? in
// Return `nil` if condition is no longer satisfied:
guard condition(state) else { return nil }
// Update current value _after_ returning from this call:
defer { state = next(state) }
// Return current value:
return state
}
return sequence(state: first, next: nextState)
}
And the first example he uses with the above function is also a good hint toward what you need:
for f in sequence(first: (0, 1), while: { $1 <= 50 }, next: { ($1, $0 + $1)}) {
print(f.1)
}
As written, that loop prints the all the Fibonacci numbers up to 34, which is the largest Fibonacci number under 50.
So... how can we generalize this further?
First, let's make a function that simply sums and returns the value:
func sumFibonacciEvens(limit: Int) -> Int {
// TODO: Implement
}
This is the basic form we want. Now, after implementing, we'd just pass in 4 million to get the answer we want, but we can easily reuse for any limit.
I'd say let's go one further though. Let's also make the "even only" part of this generic.
func sumFibonacciNumbers(lessThan limit: Int, condition: (Int) -> Bool) -> Int {
// TODO: Implement
}
Now then, for this function, we pass in the limit (again, for the case we care about, four million). But we also pass in a closure that defines what elements to sum and what elements to ignore. So for your case, calling this function would look like:
let isEven: (Int) -> Bool = { number in
return number % 2 == 0
}
let answer = sumFibonacciNumbers(lessThan: 4_000_000, condition: isEven)
This looks pretty good, right? So... how do we do it?
We're going to keep the sequence
function defined earlier exactly as is and use it in our sumFibonacciNumbers
function, which should look something like this:
public func sumFibonacciNumbers(lessThan limit: Int, condition: (Int) -> Bool) -> Int {
var sum = 0
for f in sequence(first: (0,1), while: { $1 <= limit }, next: { ($1, $0 + $1)}) where condition(f.1) {
sum += f.1
}
return sum
}