Wondering how swift closure capture works? Like i value got captured, thought j value will also be captured, but it is not. Can someone explain how this i and j get captured by swift closure?
var statements = [()->()]()
var j = 10
for i in 1...10 {
statements.append {
print(i)
print(j)
}
}
statements[2]() //prints 3 and 10
j = 20
statements[5]() //prints 6 and 20, I was expecting 6 and 10
Closure in question is capturing the reference to variable j and it will use any new value assigned to j. If you don't want to use the updated value then you have to use the below syntax where closure will capture the value(copy of variable j) instead of reference and it will not change.
var j = 10
for i in 1...10 {
statements.append { [j] in
print(i)
print(j)
}
}
Examples on my comment regarding scope of variable i & j.
If we make i as variable and change the value before invoking the closure, it will change its captured value because closure has captured the reference of variable i as below,
var j = 10
for var i in 1...10 {
statements.append { [j] in
print(i)
print(j)
}
if i == 1 {
i = 9999
statements[0]()
}
}
Output
9999
10
But if we capture the value of i & j as below then nothing will change inside the closure once it captures the values.
var j = 10
for var i in 1...10 {
statements.append { [i, j] in
print(i)
print(j)
}
if i == 1 {
i = 9999
statements[0]()
}
}
Output
1
10
Related
This question already has answers here:
Swift 3 for loop with increment
(5 answers)
Closed 5 years ago.
for example, a Java for-loop:
for(int i=0; i<5; i+=1){
//
}
convert to Swift
for index in 0..<5 {
}
but what if i+=2?
I'm new to Swift.. Maybe it's a stupid question, but will be appreciate if you answer it, thx! :-)
Check this
for index in stride(from: 0, to: 5, by: 2){
print(index)
}
You can use this way as well.
var first = 0
var last = 10
var add = 2
for i in sequence(first: first, next: { $0 + add })
.prefix(while: { $0 <= last }) {
print(i)
}
Output will be: 0,2,4,6,8,10
In case if your for loop was doing something more complex than adding constant value to index each iteration you may use something like that:
Assuming you have this for loop:
for(index = initial; condition(index); mutation(index)){
//
}
Where
initial — initial value constant of type T
condition — function (T) -> Bool, that checks if loop should end
mutation — function (T) -> T, that changes index value each iteration
Then it will be:
for index in sequence(first: initial, next: { current in
let next = mutation(current)
return condition(next) ? next : nil
}) {
//
}
...or how can I use the index inside the for loop condition
Hey people
Since we're left with no c style for loops in swift 3 I can't seem to find a way to express a bit more complex for loops so maybe you can help me out.
If I were to write this
for(int i=5; num/i > 0; i*=5)
in swift 3 how would I do that?
The closes I came by was:
for i in stride(from: 5, through: num, by: 5) where num/i > 0
but this will of course iterate 5 chunks at a time instead if i being: 5, 25, 125 etc.
Any ideas?
Thanks
Using a helper function (originally defined at Converting a C-style for loop that uses division for the step to Swift 3)
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)
}
you can write the loop as
let num = 1000
for i in sequence(first: 5, while: { num/$0 > 0 }, next: { $0 * 5 }) {
print(i)
}
A simpler solution would be a while-loop:
var i = 5
while num/i > 0 {
print(i)
i *= 5
}
but the advantage of the first solution is that the scope of the loop variable is limited to the loop body, and that the loop variable is a constant.
Swift 3.1 will provide a prefix(while:) method for sequences,
and then the helper function is no longer necessary:
let num = 1000
for i in sequence(first: 5, next: { $0 * 5 }).prefix(while: { num/$0 > 0 }) {
print(i)
}
All of above solutions are "equivalent" to the given C loop.
However, they all can crash if num is close to Int.max
and $0 * 5 overflows. If that is an issue then you have to check
if $0 * 5 fits in the integer range before doing the multiplication.
Actually that makes the loop simpler – at least if we assume that
num >= 5 so that the loop is executed at least once:
for i in sequence(first: 5, next: { $0 <= num/5 ? $0 * 5 : nil }) {
print(i)
}
For completeness: an alternative to the while loop approach is using an AnyIterator:
let num = 1000
var i = 5
for i in AnyIterator<Int>({
return i <= num ? { defer { i *= 5 }; return i }() : nil
}) {
// note that we choose to shadow the external i variable name,
// such that any access to i within this loop will only refer
// to the loop local immutable variable i.
print(i)
// e.g. i += 1 not legal, i refers to a constant here!
} /* 5
25
125
625 */
This method suffers from the same drawback as the while loop in that the loop "external" i variable persists outside and after the scope of the loop block. This external i variable is not, however, the i variable that is accessible within the loop body, as we let the loop body variable i shadow the external one, limiting access to i within the body to the immutable, temporary (loop scope local) one.
...or how can I use the index inside the for loop condition
Hey people
Since we're left with no c style for loops in swift 3 I can't seem to find a way to express a bit more complex for loops so maybe you can help me out.
If I were to write this
for(int i=5; num/i > 0; i*=5)
in swift 3 how would I do that?
The closes I came by was:
for i in stride(from: 5, through: num, by: 5) where num/i > 0
but this will of course iterate 5 chunks at a time instead if i being: 5, 25, 125 etc.
Any ideas?
Thanks
Using a helper function (originally defined at Converting a C-style for loop that uses division for the step to Swift 3)
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)
}
you can write the loop as
let num = 1000
for i in sequence(first: 5, while: { num/$0 > 0 }, next: { $0 * 5 }) {
print(i)
}
A simpler solution would be a while-loop:
var i = 5
while num/i > 0 {
print(i)
i *= 5
}
but the advantage of the first solution is that the scope of the loop variable is limited to the loop body, and that the loop variable is a constant.
Swift 3.1 will provide a prefix(while:) method for sequences,
and then the helper function is no longer necessary:
let num = 1000
for i in sequence(first: 5, next: { $0 * 5 }).prefix(while: { num/$0 > 0 }) {
print(i)
}
All of above solutions are "equivalent" to the given C loop.
However, they all can crash if num is close to Int.max
and $0 * 5 overflows. If that is an issue then you have to check
if $0 * 5 fits in the integer range before doing the multiplication.
Actually that makes the loop simpler – at least if we assume that
num >= 5 so that the loop is executed at least once:
for i in sequence(first: 5, next: { $0 <= num/5 ? $0 * 5 : nil }) {
print(i)
}
For completeness: an alternative to the while loop approach is using an AnyIterator:
let num = 1000
var i = 5
for i in AnyIterator<Int>({
return i <= num ? { defer { i *= 5 }; return i }() : nil
}) {
// note that we choose to shadow the external i variable name,
// such that any access to i within this loop will only refer
// to the loop local immutable variable i.
print(i)
// e.g. i += 1 not legal, i refers to a constant here!
} /* 5
25
125
625 */
This method suffers from the same drawback as the while loop in that the loop "external" i variable persists outside and after the scope of the loop block. This external i variable is not, however, the i variable that is accessible within the loop body, as we let the loop body variable i shadow the external one, limiting access to i within the body to the immutable, temporary (loop scope local) one.
...or how can I use the index inside the for loop condition
Hey people
Since we're left with no c style for loops in swift 3 I can't seem to find a way to express a bit more complex for loops so maybe you can help me out.
If I were to write this
for(int i=5; num/i > 0; i*=5)
in swift 3 how would I do that?
The closes I came by was:
for i in stride(from: 5, through: num, by: 5) where num/i > 0
but this will of course iterate 5 chunks at a time instead if i being: 5, 25, 125 etc.
Any ideas?
Thanks
Using a helper function (originally defined at Converting a C-style for loop that uses division for the step to Swift 3)
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)
}
you can write the loop as
let num = 1000
for i in sequence(first: 5, while: { num/$0 > 0 }, next: { $0 * 5 }) {
print(i)
}
A simpler solution would be a while-loop:
var i = 5
while num/i > 0 {
print(i)
i *= 5
}
but the advantage of the first solution is that the scope of the loop variable is limited to the loop body, and that the loop variable is a constant.
Swift 3.1 will provide a prefix(while:) method for sequences,
and then the helper function is no longer necessary:
let num = 1000
for i in sequence(first: 5, next: { $0 * 5 }).prefix(while: { num/$0 > 0 }) {
print(i)
}
All of above solutions are "equivalent" to the given C loop.
However, they all can crash if num is close to Int.max
and $0 * 5 overflows. If that is an issue then you have to check
if $0 * 5 fits in the integer range before doing the multiplication.
Actually that makes the loop simpler – at least if we assume that
num >= 5 so that the loop is executed at least once:
for i in sequence(first: 5, next: { $0 <= num/5 ? $0 * 5 : nil }) {
print(i)
}
For completeness: an alternative to the while loop approach is using an AnyIterator:
let num = 1000
var i = 5
for i in AnyIterator<Int>({
return i <= num ? { defer { i *= 5 }; return i }() : nil
}) {
// note that we choose to shadow the external i variable name,
// such that any access to i within this loop will only refer
// to the loop local immutable variable i.
print(i)
// e.g. i += 1 not legal, i refers to a constant here!
} /* 5
25
125
625 */
This method suffers from the same drawback as the while loop in that the loop "external" i variable persists outside and after the scope of the loop block. This external i variable is not, however, the i variable that is accessible within the loop body, as we let the loop body variable i shadow the external one, limiting access to i within the body to the immutable, temporary (loop scope local) one.
I want to use a closure as a condition for a while loop. This is what I have:
var x: Int = 0
var closure = {() -> Bool in return x > 10}
while closure {
x += 1
println(x) // never prints
}
It never prints anything. If I change it to closure(), it doesn't work either.
Any help would be appreciated.
There are two problems here.
Firstly, as written, your code won't even compile. You need to change while closure to while closure().
Second, the bigger problem, your closure logic is wrong. x > 10 never returns true because x is never greater than 10. Flip the sign over and it'll work.
Swift 2
var x = 0
var closure = { () -> Bool in return x < 10 }
while closure() {
++x
print(x)
}
Swift 1.2
var x = 0
var closure = { () -> Bool in return x < 10 }
while closure() {
++x
println(x)
}
Two issues:
Your logic is backwards. You want to print while x is less than 10, so:
when you call a closure directly you do so as you would a function, i.e. with parenthesis.
Updated code, tested with Swift 2.0:
var x: Int = 0
var closure = {() -> Bool in return x < 10}
while closure() {
x += 1
print(x)
}
You need to call the closure with (), and your condition is the wrong way around so that it's false at the beginning (it should be x < 10, not x > 10). Change to:
var x = 0
var closure: () -> Bool = { x < 10 }
while closure() {
++x
print(x)
}
Take advantage of abbreviation opportunities to make your code more concise and elegant.
var x = 0
let closure = { x < 10 }
while closure() {
x++
}
x // 10