Closures can capture constants and variables from the context in which they are defined.
In swift, The simplest example of capturing a value is a nested function, for example:
1 func makeincrementer (forincrement amount:int), Int {2 var0 3 func incrementer () Int {4 runningtotal + = Amount5 return runningtotal6 } 7 return incrementer8 }
In this example Incrementer () captures two values, respectively, amount, runningtotal. You can run it and observe the Results:
1Let Incrementbyten = Makeincrementer (forincrement:Ten)2Print (incrementbyten ())//Ten3Print (incrementbyten ())//20
4Let Incrementbynine = Makeincrementer (forincrement:9)5Print (incrementbynine ())//96Print (incrementbynine ())//18
7Print (incrementbyten ())// -
Note: If you assign a closure to a property of a class instance, and the closure captures the value by pointing to the member (refer Fo) instance or instance, then there is a strong reference ring between the closure and the Instance.
Closures are reference types (Reference Types)
Closures and functions are reference types.
Nonescaping Closures
When a closure is passed as a parameter to a function, but when called after the function returns, we say that a closure is Escaped. When you declare a function with a closure as a parameter, you can write @nonescape before the parameter type to imply that the closure does not allow Escape. Such as:
1 func somefunctionwithnonescapingclosure (closure: @noescape (), Void) {2 Closure ()3 }
Take a closure tag with @nonescape to let you implicitly reference (refer to) self in the closure, and look at this example:
1 classSomeClass {2 varx =Ten3 func dosomething () {4Somefunctionwithnonescapingclosure {x = $ }5Somefunctionwithescapingclosure {self.x = - }6 }7 }8 9Let instance =SomeClass ()Ten instance.dosomething () one Print (instance.x) a //Prints " - -completionhandlers.first?() the Print (instance.x) - //Prints "Autoclosures
An autoclosure was a closure that's automatically created to wrap an expression That's being passed as an argument to a Fu Nction. It doesn ' t take any arguments, and when it's called, it returns the value of the expression that ' s wrapped inside of it.
Autoclosures can delay the calculation (delay Evaluation) because the code inside the closure is not run until the closure is Called. Lazy computing is useful for code that has side effects or computationally expensive, because you can control when your code is Evaluation.
1 varCustomersinline = ["Chris","Alex","Ewa","Barry","Daniella"]2 Print (customersinline.count)3 //Prints "5"4 5Let Customerprovider = {customersinline.remove (at:0) }6 Print (customersinline.count)7 //Prints "5"8 9Print"now serving \ (customerprovider ())!")Ten //Prints "now serving chris!" one Print (customersinline.count) a //Prints "4"
can also be passed to a parameter:
1 // Customersinline is ["Alex", "Ewa", "Barry", "daniella"] 2 func serve (customer customerprovider: () String) {3 print ("now Serving \ (customerprovider ())! " )4}50)})6// Prints "now Serving alex!"
Using @autoclosure:
1 // Customersinline is ["Ewa", "Barry", "daniella"] 2 func serve (customer customerprovider: @autoclosure (), String) {3 print (" now serving \ (customerprovider ())! " )4}50))6//
Note: misuse of autoclosure can make your code obscure.
The @autoclosure property implies the @nonescape property, and if you want a autoclosure allow esacpe, you can use @autoclosure (escaping) , such as:
1 //Customersinline is ["Barry", "daniella"]2 varCustomerproviders: [()-String] = []3Func collectcustomerproviders (_ customerprovider: @autoclosure (escaping) ()String) {4 customerproviders.append (customerprovider)5 }6Collectcustomerproviders (customersinline.remove (at:0))7Collectcustomerproviders (customersinline.remove (at:0))8 9Print"collected \ (customerproviders.count) closures.")Ten //Prints "collected 2 closures." one forCustomerproviderinchCustomerproviders { aPrint"now serving \ (customerprovider ())!") - } - //Prints "now serving barry!" the //Prints "now serving daniella!"
Closure of Swift (ii): capture value