Two returns in Closures - swift

I'm New to swift here. Was reading closures on weheartswift. There is one section talking about capturing value. Two questions here:
How do I understand the two returns here?
Why this closure captures the previous value from variable, shouldn't i be initialized every time from the value of start, which is always 0?
Code :
func makeIterator(start: Int, step: Int) -> () -> Int {
var i = start
return {
i += step
return i
}
}
var iterator = makeIterator(0, 1)
iterator() // 1
iterator() // 2
iterator() // 3

Like this:
var i = start
return /*the following is a closure that returns an Int:*/{
i += step
return i
}/*< end of closure*/
What's being returned is a closure. { return i } is actually a function that returns the value of i.
You could also write it this way:
func makeIterator(start: Int, step: Int) -> () -> Int {
var i = start
func iterate() -> Int {
i += step
return i
}
return iterate
}
A closure is functionality + state. The "state" here is the local variable i.
The closure "closes over" i, meaning that each time the closure is executed it will be looking at the same i which it can modify. This is true even after the closure is returned from the function. When you call it multiple times, it updates its internal state and returns the new value.

It is seems like function returns function as its value. returned function doesn't take any argument and returns a integer value. I recommend you to have a look at Swift documentation.

Related

Difference between Closure Functions and Functions

I'm trying to learn swift and came across closures got the hang of it but still I have a question to ask, couldn't find any answers on the internet and I'm not sure if it's appropriate to ask here but I really need an answer on this.
say we have the following class
class Human{
var gender:String?
private func fCheckGender(pGender:String?){
guard pGender != nil else {
print("Gender not specified")
return
}
if pGender == "M"{
print("Male")
}
else if pGender == "F"{
print("Female")
}
else{
print("gender Unknown")
}
}
private func cCheckGender( pGender:#autoclosure ()->(String?)){
guard pGender() != nil else {
print("Gender not specified")
return
}
if pGender() == "M"{
print("Male")
}
else if pGender() == "F"{
print("Female")
}
else{
print("gender Unknown")
}
}
func MyCheckGender(){
fCheckGender(pGender: gender)
cCheckGender(pGender: gender)
}
}
var myHuman:Human = Human()
myHuman.gender = "M"
myHuman.MyCheckGender()
I would like to know the difference of
fCheckGender and cCheckGender when and where should I use the closures
Thanks in advance!
P.S I have intentionally used void->String ()->(String?)
I only want to learn the difference in this scenario. I'm sorry for my bad english
Closure:
Closure is a block of code, treat it like an unnamed function.
When a closure is passed as an argument, the closure is not evaluated till the code inside the function invokes the argument.
Auto closure:
Auto closure is just a closure which packages the parameter values along with it.
When you define an autoclosure, there would be no parameters to the closure.
Difference between fCheckGender and cCheckGender:
fCheckGender takes a String value as an argument.
cCheckGender takes closure as an argument.
When cCheckGender is invoked, the closure is passed an argument, at this point, the closure is only passed as an argument, the closure is not executed. Only when the closure parameter is used inside the function, the closure gets executed.
The example you have stated might not be the best one to demonstrate the difference.
Let's consider a different example:
Example:
func add(a: Int, b: Int) -> Int {
print("add")
return a + b
}
func f1(pValue: Int) {
print("f1")
print("value = \(pValue)")
}
func f2(pClosure: (Int, Int) -> Int, pA: Int, pB: Int) {
print("f2")
let value = pClosure(pA, pB)
print("value = \(value)")
}
//In autoclosure the closure always takes no parameters, because the closure is packaged with parameter values while invoking
func f3(pClosure: #autoclosure () -> Int) {
print("f3")
let value = pClosure()
print("value = \(value)")
}
f1(pValue: add(a: 10, b: 20))
print("=====================\n")
f2(pClosure: add, pA: 10, pB: 20)
print("=====================\n")
f3(pClosure: add(a: 10, b: 20))
print("=====================\n")
Output:
add
f1
value = 30
=====================
f2
add
value = 30
=====================
f3
add
value = 30
=====================
Explanation of example:
In the function f1 pValue is an Int value.
So when f1 is invoked, the add is evaluated
In the functions f2 and f3 pClosure is a closure.
pClosure (closure) is not evaluated till it is invoked inside the function.
Note:
Focus on f3 first which accepts a closure as the argument.
Once you fully understand f3, then examine f2.
Auto closure captures the parameter values when it is invoked and later uses it.
Why and when do we need to pass a closure instead of a value:
There might be a scenario, where you would like to defer the execution of add till the time the function f2 invokes it.
There might be a scenario, where you make an asynchronous request and you want a piece of code to execute when the request completes. In this case you might pass a closure. (Closure need not always return a value, it is an unnamed function, so it can accept parameters)
Why and when do we need to an autoclosure:
When you want to defer the execution of add and also capture the value of it's parameters.
Suggestion:
Though time consuming, it is best for you to go through the Swift documentation from the beginning to fully understand it.
Reference:
As Hamish has pointed please read about closures, then auto closures from https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html
Function
In the function createUser the firebase runs background of the app so when the user enters button of the login app the function "RegisteredButtonPressed" is trigged.
Inside the registeredButtonPressed function the username & password are given by the user if its correct then "completion" function is trigerred. After that "completed" function will be activated the it prints into console.
same code concept I have written in closure.
class Firebase {
func createUser (username: String, password: String, completion: (Bool, Int) -> Void) {
let isSuccess = true
let userID = 123
completion(isSuccess, userID)
}
}
class MYApp {
func registerButtonPressed () {
let firebase = Firebase()
firebase.createUser(username: "Gullu", password: "123456", completion: completed(isSuccess:userID:))
}
func completed (isSuccess: Bool, userID: Int) {
print("Registration id is success \(isSuccess)")
print("User id is \(userID)")
}
}
Closure
Converting func keyword to closure
remove the func keyword & name of function
Bring the starting curly bracket after func starts in the beginning (in "func completed" after userid: Int a curly bracket is there , so bring it before the second bracket starts).
Replace it with "in" keyword
instead of calling the completed function cut paste the 3rd point above code & paste it to completion inside firebase.creativeUser
Delete the completion parameter to make it trailing closure
class MYApp {
func registerButtonPressed () {
let firebase = Firebase()
firebase.createUser(username: "Gullu", password: "123456") {
(isSuccess: Bool, userID: Int) in
print("Registration id is success \(isSuccess)")
print("User id is \(userID)")
}
}
}

what does 'condition' mean here in swift tutorial ----function?

I know that in the first line, we can use lessThanTen(number: Int) to replace (int), and contidion means a label, but in the third line: * why dont we use if condition : (item) to replace if condition(item), since condition is a label.
Condition is the method that you're receiving on that method, if you look at that method signature:
condition: (int) -> Bool
which means that you're receiving a condition that can be called using an argument of Int type and will return a bool. Anywhere, inside:
hasAnyMatches
you'll be able to use
condition(anyInt)
Now if you look at the method caller:
hasAnyMatches(list: numbers, condition: lessThanTen)
so, you're saying that the 'condition' on 'hasAnyMatches' will be 'lessThanTen'. Which means that in your
if condition(item)
What really is happening is:
if lessThanTen(item)
I hope it made it clearer!
condition is a Bool-returning closure supplied to hasAnyMatches that needs to be called to yield a boolean value. The closure takes a single argument of type Int, which is the same type as the elements of list. Hence, we call the supplied (Int) -> Bool closure on each item, and in case condition applied to an item returns true, we cut the traversal over the list items short and return true from the function.
Using functional programming tecniques, we could make use of a reduce operation on list to compress the implementation of hasAnyMatches:
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
return list.reduce(false) { $0 || condition($1) }
}
Or, even better (allowing exit return as in the original loop), as described by #Hamish in the comments belows (thanks!), using contains
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
return list.contains(where: condition)
}
Example usage:
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
print(hasAnyMatches(list: numbers, condition: lessThanTen)) // true

Updating an inout param async does not update reference [duplicate]

I'm trying to insert functions with inout parameter to append data received from async callback to an outside array. However, it does not work. And I tried everything I know to find out why - with no luck.
As advised by #AirspeedVelocity, I rewrote the code as follows to remove unnecessary dependencies. I also use an Int as the inout parameter to keep it simple.The output is always:
c before: 0
c after: 1
I'm not able to figure out what goes wrong here.
func getUsers() {
let u = ["bane", "LiweiZ", "rdtsc", "ssivark", "sparkzilla", "Wogef"]
var a = UserData()
a.userIds = u
a.dataProcessor()
}
struct UserData {
var userIds = [String]()
var counter = 0
mutating func dataProcessor() -> () {
println("counter: \(counter)")
for uId in userIds {
getOneUserApiData(uriBase + "user/" + uId + ".json", &counter)
}
}
}
func getOneUserApiData(path: String, inout c: Int) {
var req = NSURLRequest(URL: NSURL(string: path)!)
var config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
var session = NSURLSession(configuration: config)
var task = session.dataTaskWithRequest(req) {
(data: NSData!, res: NSURLResponse!, err: NSError!) in
println("c before: \(c)")
c++
println("c after: \(c)")
println("thread on: \(NSThread.currentThread())")
}
task.resume()
}
Thanks.
Sad to say, modifying inout parameter in async-callback is meaningless.
From the official document:
Parameters can provide default values to simplify function calls and can be passed as in-out parameters, which modify a passed variable once the function has completed its execution.
...
An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value.
Semantically, in-out parameter is not "call-by-reference", but "call-by-copy-restore".
In your case, counter is write-backed only when getOneUserApiData() returns, not in dataTaskWithRequest() callback.
Here is what happened in your code
at getOneUserApiData() call, the value of counter 0 copied to c1
the closure captures c1
call dataTaskWithRequest()
getOneUserApiData returns, and the value of - unmodified - c1 is write-backed to counter
repeat 1-4 procedure for c2, c3, c4 ...
... fetching from the Internet ...
callback is called and c1 is incremented.
callback is called and c2 is incremented.
callback is called and c3 is incremented.
callback is called and c4 is incremented.
...
As a result counter is unmodified :(
Detailed explaination
Normally, in-out parameter is passed by reference, but it's just a result of compiler optimization. When closure captures inout parameter, "pass-by-reference" is not safe, because the compiler cannot guarantee the lifetime of the original value. For example, consider the following code:
func foo() -> () -> Void {
var i = 0
return bar(&i)
}
func bar(inout x:Int) -> () -> Void {
return {
x++
return
}
}
let closure = foo()
closure()
In this code, var i is freed when foo() returns. If x is a reference to i, x++ causes access violation. To prevent such race condition, Swift adopts "call-by-copy-restore" strategy here.
Essentially it looks like you’re trying to capture the “inout-ness” of an input variable in a closure, and you can’t do that – consider the following simpler case:
// f takes an inout variable and returns a closure
func f(inout i: Int) -> ()->Int {
// this is the closure, which captures the inout var
return {
// in the closure, increment that var
return ++i
}
}
var x = 0
let c = f(&x)
c() // these increment i
c()
x // but it's not the same i
At some point, the variable passed in ceases to be x and becomes a copy. This is probably happening at the point of capture.
edit: #rintaro’s answer nails it – inout is not in fact semantically pass by reference
If you think about it this makes sense. What if you did this:
// declare the variable for the closure
var c: ()->Int = { 99 }
if 2+2==4 {
// declare x inside this block
var x = 0
c = f(&x)
}
// now call c() - but x is out of scope, would this crash?
c()
When closures capture variables, they need to be created in memory in such a way that they can stay alive even after the scope they were declared ends. But in the case of f above, it can’t do this – it’s too late to declare x in this way, x already exists. So I’m guessing it gets copied as part of the closure creation. That’s why incrementing the closure-captured version doesn’t actually increment x.
I had a similar goal and ran into the same issue where results inside the closure were not being assigned to my global inout variables. #rintaro did a great job of explaining why this is the case in a previous answer.
I am going to include here a generalized example of how I worked around this. In my case I had several global arrays that I wanted to assign to within a closure, and then do something each time (without duplicating a bunch of code).
// global arrays that we want to assign to asynchronously
var array1 = [String]()
var array2 = [String]()
var array3 = [String]()
// kick everything off
loadAsyncContent()
func loadAsyncContent() {
// function to handle the query result strings
// note that outputArray is an inout parameter that will be a reference to one of our global arrays
func resultsCallbackHandler(results: [String], inout outputArray: [String]) {
// assign the results to the specified array
outputArray = results
// trigger some action every time a query returns it's strings
reloadMyView()
}
// kick off each query by telling it which database table to query and
// we're also giving each call a function to run along with a reference to which array the results should be assigned to
queryTable("Table1") {(results: [String]) -> Void in resultsCallbackHandler(results, outputArray: &self.array1)}
queryTable("Table2") {(results: [String]) -> Void in resultsCallbackHandler(results, outputArray: &self.array2)}
queryTable("Table3") {(results: [String]) -> Void in resultsCallbackHandler(results, outputArray: &self.array3)}
}
func queryTable(tableName: String, callback: (foundStrings: [String]) -> Void) {
let query = Query(tableName: tableName)
query.findStringsInBackground({ (results: [String]) -> Void in
callback(results: results)
})
}
// this will get called each time one of the global arrays have been updated with new results
func reloadMyView() {
// do something with array1, array2, array3
}
#rintaro perfectly explained why it doesn't work, but if you really want to do that, using UnsafeMutablePointer will do the trick:
func getOneUserApiData(path: String, c: UnsafeMutablePointer<Int>) {
var req = NSURLRequest(URL: NSURL(string: path)!)
var config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
var session = NSURLSession(configuration: config)
var task = session.dataTaskWithRequest(req) {
(data: NSData!, res: NSURLResponse!, err: NSError!) in
println("c before: \(c.memory)")
c.memory++
println("c after: \(c.memory)")
println("thread on: \(NSThread.currentThread())")
}
task.resume()
}

In Swift,there's no way to get the returned function's argument names?

When a function's return value is another function,there's no way to get the returned function's argument names.Is this a pitfall of swift language?
For example:
func makeTownGrand(budget:Int,condition: (Int)->Bool) -> ((Int,Int)->Int)?
{
guard condition(budget) else {
return nil;
}
func buildRoads(lightsToAdd: Int, toLights: Int) -> Int
{
return toLights+lightsToAdd
}
return buildRoads
}
func evaluateBudget(budget:Int) -> Bool
{
return budget > 10000
}
var stopLights = 0
if let townPlan = makeTownGrand(budget: 30000, condition: evaluateBudget)
{
stopLights = townPlan(3, 8)
}
Be mindful of townPlan,townPlan(lightsToAdd: 3, toLights: 8) would be much more sensible to townPlan(3, 8), right?
You're correct. From the Swift 3 release notes:
Argument labels have been removed from Swift function types... Unapplied references to functions or initializers no longer carry argument labels.
Thus, the type of townPlan, i.e. the type returned from calling makeTownGrand, is (Int,Int) -> Int — and carries no external argument label information.
For a full discussion of the rationale, see https://github.com/apple/swift-evolution/blob/545e7bea606f87a7ff4decf656954b0219e037d3/proposals/0111-remove-arg-label-type-significance.md

Inout parameter in async callback does not work as expected

I'm trying to insert functions with inout parameter to append data received from async callback to an outside array. However, it does not work. And I tried everything I know to find out why - with no luck.
As advised by #AirspeedVelocity, I rewrote the code as follows to remove unnecessary dependencies. I also use an Int as the inout parameter to keep it simple.The output is always:
c before: 0
c after: 1
I'm not able to figure out what goes wrong here.
func getUsers() {
let u = ["bane", "LiweiZ", "rdtsc", "ssivark", "sparkzilla", "Wogef"]
var a = UserData()
a.userIds = u
a.dataProcessor()
}
struct UserData {
var userIds = [String]()
var counter = 0
mutating func dataProcessor() -> () {
println("counter: \(counter)")
for uId in userIds {
getOneUserApiData(uriBase + "user/" + uId + ".json", &counter)
}
}
}
func getOneUserApiData(path: String, inout c: Int) {
var req = NSURLRequest(URL: NSURL(string: path)!)
var config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
var session = NSURLSession(configuration: config)
var task = session.dataTaskWithRequest(req) {
(data: NSData!, res: NSURLResponse!, err: NSError!) in
println("c before: \(c)")
c++
println("c after: \(c)")
println("thread on: \(NSThread.currentThread())")
}
task.resume()
}
Thanks.
Sad to say, modifying inout parameter in async-callback is meaningless.
From the official document:
Parameters can provide default values to simplify function calls and can be passed as in-out parameters, which modify a passed variable once the function has completed its execution.
...
An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value.
Semantically, in-out parameter is not "call-by-reference", but "call-by-copy-restore".
In your case, counter is write-backed only when getOneUserApiData() returns, not in dataTaskWithRequest() callback.
Here is what happened in your code
at getOneUserApiData() call, the value of counter 0 copied to c1
the closure captures c1
call dataTaskWithRequest()
getOneUserApiData returns, and the value of - unmodified - c1 is write-backed to counter
repeat 1-4 procedure for c2, c3, c4 ...
... fetching from the Internet ...
callback is called and c1 is incremented.
callback is called and c2 is incremented.
callback is called and c3 is incremented.
callback is called and c4 is incremented.
...
As a result counter is unmodified :(
Detailed explaination
Normally, in-out parameter is passed by reference, but it's just a result of compiler optimization. When closure captures inout parameter, "pass-by-reference" is not safe, because the compiler cannot guarantee the lifetime of the original value. For example, consider the following code:
func foo() -> () -> Void {
var i = 0
return bar(&i)
}
func bar(inout x:Int) -> () -> Void {
return {
x++
return
}
}
let closure = foo()
closure()
In this code, var i is freed when foo() returns. If x is a reference to i, x++ causes access violation. To prevent such race condition, Swift adopts "call-by-copy-restore" strategy here.
Essentially it looks like you’re trying to capture the “inout-ness” of an input variable in a closure, and you can’t do that – consider the following simpler case:
// f takes an inout variable and returns a closure
func f(inout i: Int) -> ()->Int {
// this is the closure, which captures the inout var
return {
// in the closure, increment that var
return ++i
}
}
var x = 0
let c = f(&x)
c() // these increment i
c()
x // but it's not the same i
At some point, the variable passed in ceases to be x and becomes a copy. This is probably happening at the point of capture.
edit: #rintaro’s answer nails it – inout is not in fact semantically pass by reference
If you think about it this makes sense. What if you did this:
// declare the variable for the closure
var c: ()->Int = { 99 }
if 2+2==4 {
// declare x inside this block
var x = 0
c = f(&x)
}
// now call c() - but x is out of scope, would this crash?
c()
When closures capture variables, they need to be created in memory in such a way that they can stay alive even after the scope they were declared ends. But in the case of f above, it can’t do this – it’s too late to declare x in this way, x already exists. So I’m guessing it gets copied as part of the closure creation. That’s why incrementing the closure-captured version doesn’t actually increment x.
I had a similar goal and ran into the same issue where results inside the closure were not being assigned to my global inout variables. #rintaro did a great job of explaining why this is the case in a previous answer.
I am going to include here a generalized example of how I worked around this. In my case I had several global arrays that I wanted to assign to within a closure, and then do something each time (without duplicating a bunch of code).
// global arrays that we want to assign to asynchronously
var array1 = [String]()
var array2 = [String]()
var array3 = [String]()
// kick everything off
loadAsyncContent()
func loadAsyncContent() {
// function to handle the query result strings
// note that outputArray is an inout parameter that will be a reference to one of our global arrays
func resultsCallbackHandler(results: [String], inout outputArray: [String]) {
// assign the results to the specified array
outputArray = results
// trigger some action every time a query returns it's strings
reloadMyView()
}
// kick off each query by telling it which database table to query and
// we're also giving each call a function to run along with a reference to which array the results should be assigned to
queryTable("Table1") {(results: [String]) -> Void in resultsCallbackHandler(results, outputArray: &self.array1)}
queryTable("Table2") {(results: [String]) -> Void in resultsCallbackHandler(results, outputArray: &self.array2)}
queryTable("Table3") {(results: [String]) -> Void in resultsCallbackHandler(results, outputArray: &self.array3)}
}
func queryTable(tableName: String, callback: (foundStrings: [String]) -> Void) {
let query = Query(tableName: tableName)
query.findStringsInBackground({ (results: [String]) -> Void in
callback(results: results)
})
}
// this will get called each time one of the global arrays have been updated with new results
func reloadMyView() {
// do something with array1, array2, array3
}
#rintaro perfectly explained why it doesn't work, but if you really want to do that, using UnsafeMutablePointer will do the trick:
func getOneUserApiData(path: String, c: UnsafeMutablePointer<Int>) {
var req = NSURLRequest(URL: NSURL(string: path)!)
var config = NSURLSessionConfiguration.ephemeralSessionConfiguration()
var session = NSURLSession(configuration: config)
var task = session.dataTaskWithRequest(req) {
(data: NSData!, res: NSURLResponse!, err: NSError!) in
println("c before: \(c.memory)")
c.memory++
println("c after: \(c.memory)")
println("thread on: \(NSThread.currentThread())")
}
task.resume()
}