Closures in Swift (closure) detailed
Before Swift was released, everyone used the OC language to write programs on cocoa, one of which was often discussed-Block has always been popular. In Swift, there is also a role that is used when developers need to execute asynchronously after a syntax-Closure. Chinese translation is closed.
The complete use of closures, which can be performed asynchronously, depends on the capture of the variables and constants of the closure itself. Closures capture and store references to any constants and variables in the context in which they are defined, which means that you can obtain all of the previous environment variables at any time when the closure is executed asynchronously. In fact, closures are similar to anonymous functions in swift, and in the previous article, higher-order functions and nested functions, which are inseparable from those of closures, are described. For example, the simplest closure is a high-order function, but when the closure is a parameter variable, the closure is anonymous and written. Closures are more lightweight when it comes to general higher-order functions.
This article describes several types of closures and the characteristics of some closures.
First, the basic form of closures
This is the most basic form of closures:
{ (parameters) -> return type in
statements
}
Closure, contains three elements: parameters, return type, closure body. where parameters and return types can be ignored, but a closure must exist, in fact, even in the closure of the body, nothing is written, the closure itself or in the form of no execution of any code exists.
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
This is a high-order function, and is also a basic use of closures. Contains the parameters and types, returns the value type, and closes the package body.
We can write in the form of a shorthand closure, using inline notation:
Reversednames = names.sorted (by: {(s1:string, s2:string)-Bool in return s1 > s2})
In closures, because of the reference to variables and constants of the context and type inference, in fact, the type is fixed for the parameters of the closure and of course the returned type is fixed, and Swift allows the developer to omit it when writing. Just like this:
Reversednames = names.sorted (by: {S1, s2 in return s1 > s2})
If the closure is a single expression (only one execution statement), you can even omit the return
Reversednames = names.sorted (by: {S1, s2 in S1 > s2})
Another feature of Swift's closures is that Swift automatically provides a shorthand parameter name for the inline closure, which can be used to reference the value of the closure parameter by name $0,$ 1,$ 2.
If you use these shorthand parameter names in a closure expression, you can omit the closure's argument list from its definition and infer the number and type of shorthand parameter names based on the expected function type. The In keyword can also be omitted because the closure expression consists entirely of its body:
Reversednames = names.sorted (by: {$ > $})
This is not perfect enough, if the ">" symbol overload, so that $ > directly with > Instead of is more concise? Of course, in fact, the > in Swift has been defined > refers to a comparison between two swift strings and returns a bool value. So our final version should look like this:
Reversednames = names.sorted (by: >)
Second, trailing closure package
If you define a closure as the last parameter of a function, and because it contains other parameters, which makes the function very long, you can write the closure in a short way. A function like this:
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
If we invoke the use, this should be the case:
someFunctionThatTakesAClosure(closure: {
// closure‘s body goes here
})
In cases like this, we consider it to constitute a trailing closure, and for a trailing closure, there is another easier way to write:
someFunctionThatTakesAClosure() {
// trailing closure‘s body goes here
}
Note that at this time, the label closure of the closure should be omitted.
In this case, we can write a special version of the final version of the closure:
Reversednames = names.sorted (>)
Trailing closures are used in a long-length closure, which works better. You can use this technique to write very short, elegant code.
Third, closure capture value
In fact, the nature of closures is similar to a nested function, which has the same ability as nested functions: Gets local variables and constants in a closure: it can get all the arguments to the external function, and any constants and variables defined within the outer function.
Here's a nested function, which acts like a closure:
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
Incrementer can be used to obtain the values of amount and runingtotal.
Call:
Let incrementByTen = makeIncrementer(forIncrement: 10) // Bind the reference, guarantee that it will not disappear when it is used up.
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30
Incrementer this nested function value changes the value of runningtotal while receiving the changing amount.
If you change a function variable reference, the value will be refreshed:
let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven()
// returns a value of 7
The reference to the closure is associative. As with the general variables:
let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// returns a value of 50
Four, Escape closure package
In the process of network requests, most of the time is asynchronous operation, the general closure, although the closure of the closure of the package (closure implementation), but in the request callback, the closure may not be called. The reason is that it may be released or may be modified.
If you need to ensure that an asynchronous call is made, you need to add @escaping tag before the closure parameter .
The addition of @escaping tags means that if you need to access your own variables, you must include your own references (or their own properties, variables, and so on) within the closure.
The following is a comparison of two types of closures that are labeled:
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
Both calls:
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { self.x = 100 }
someFunctionWithNonescapingClosure { x = 200 }
}
}
The default closures are non-escape closures.
Five, Autoclosures automatic closure
The automatic closure means that when a closure is a parameter of a function, the timing of the execution of the contents of the closure depends on who. The normal closure will be executed when the packet is read, and the automatic closure, when read, will be the closure as its parameter type processing, only wait until the closure of the execution of the closure of the contents of the packet.
// customersInLine is ["Ewa", "Barry", "Daniella"] func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0)) // Prints "Now serving Ewa!"
Before execution, Customerprovider is treated as a () String, without involving the processing within the closure body. If you do not use @autoclosure, then the function handles the contents of the closure body.
The daily development can be used:
public func Dlog( item:@autoclosure ()->Any){
#if DEBUG
print(item())
#else
#endif
}
The default automatic closure is non-escape closure, if you want to become a escape closure, you can be as follows:
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
customerProviders.append(customerProvider)
}
Closures in Swift (closure) detailed