Closures are functional self-contained modules that can be passed and used in Code. Closures in Swift are similar to those in the blocks in C and Objective-c and Lambdas in other programming languages.
Closures can capture and store references to arbitrary constants and variables in the context in which they are located.
This is called closed merge wrapped with these constants and variables, commonly known as Closures. Swift manages the memory operations involved in the capture process for YOU.
Note: Suppose you are not familiar with the concept of capture (capturing) and don't worry about it. It will be described in detail later.
The global and nested functions described in the SWIFT Functions section are actually special Closures. Closures are taken for example in one of the following three forms:
A global function is a closed packet that has a name but does not capture whatever value
A nested function is a closure that has a name and is capable of capturing values within its enclosing function domain
A closure expression is a non-named closure that uses lightweight syntax to capture variables or constant values in its Context.
Swift's closure expressions have a concise style and are encouraged to implement syntax optimizations in common scenarios. Main optimizations such as the Following:
Use context to determine the number of parameters and return value types
Single-expression (single-expression) closures can omit return keyword
Abbreviation for the name of the participant
Trailing closed Packet Syntax
The closure expression nesting function is a convenient way to name and define self-contained code modules in more complex functions. of course, It is sometimes very useful to write small, non-fully defined and named class function structures, especially when dealing with functions and requiring additional functions to be used as a parameter to the Function.
A closure expression is a way to construct an inline closure using concise syntax. The closure expression provides some syntax optimizations. Makes writing closures simple and Straightforward.
The following example of a closure expression demonstrates the way the sort function is defined and syntax optimized by using several iterations. Each iteration describes the same functionality in a more concise way.
The sort function Swift standard library provides a sort function that sorts the values in an array of known types according to the sort closures you provide.
Once sorted, the function returns a new array with the same size as the original array, which includes the same type elements that have been sorted correctly.
The following closure expression demonstrates the sample uses the sort function to sort an array of type String alphabetically, and the following is the initial array value:
Let names = ["Chris", "Alex", "Ewa", "Barry", "daniella"]
The sort function has two parameters:
An array of known type Values.
A closure that uses two parameters of the contents of the same type of array and returns a Boolean value that indicates whether the first value is placed before or after the second value in the sort Order. If the first value should be preceded by a second value, the closure needs to return true, otherwise false is Returned.
The sample sorts an array of type string, so the sort closure needs to be a function (string, string), type Bool.
One way to provide a sort closure is to compose a normal function that conforms to its type requirements and pass it in as the second parameter of the sort function:
Func backwards (s1:string, s2:string)- > Bool {
return s1 > S2
}
var reversed = sort (names, backwards)
//reversed is equal to [" Ewa "," Daniella "," Chris "," Barry "," Alex "]
assumes that the first string (s1) is greater than the second string (s2). The backwards function returns true, indicating that S1 should be present in the new array before the s2. "greater than" in the character indicates "appears in alphabetical order." This means that the letter "B" is greater than the letter "A" and the string "Tom" is greater than the string "Tim". It will be sorted in reverse alphabetical order. "Barry" will be ranked after "Alex", one analogy.
however, This is a rather lengthy way, essentially simply writing a single-expression function (a > b). In the following example, a closed-expression syntax is used to better construct an inline sort Closure. The
closure expression syntax for the closure expression syntax has the following general Form:
{(parameters)-returntype in
statements
}
The
Closure expression syntax can use constants, variables, and inout types as parameters, but does not provide a default Value. It is also possible to use variable parameters at the end of the list of References. Tuples can also be used as parameters and return Values.
The following example shows the code for the corresponding closure expression version number of the previous backwards function:
Reversed = sort (names, {(s1:string, s2:string), Bool in
return s1 > S2
})
It is important to note that inline closure parameters and return value type declarations are the same as the backwards function type Declarations. In both of these ways, the type of bool (s1:string, S2:string) is Written. In an inline closure expression, however, Both the function and the return value type are written in curly braces, not outside the curly Braces.
The function body part of the closure is introduced by keyword IN. The keyword indicates that the Closure's parameters and return value type definitions are complete and the closure function body is about to Begin.
Because the function body part of the closure is so short that it can be rewritten into one line of code:
Reversed = sort (names, {(s1:string, s2:string), Bool in return s1 > S2})
This indicates that the overall invocation of the sort function remains unchanged. A pair of parentheses still wraps the entire set of parameters in the Function.
And one of the parameters has now become an inline closure (compared to the code for the backwards version number).
Depending on the context of the type because the sort closure is passed in as a function parameter, Swift can determine the type of its parameters and the return Value. Sort expects the second parameter to be a function of type (string, string), bool, so in fact string, string, and bool types do not need to be part of the definition of a closure expression.
Since all types can be judged correctly, the return arrows and the parentheses around the parameters can be omitted:
Reversed = sort (names, {s1, s2 in return s1 > S2})
In fact, when a closure constructed by an inline closure expression is passed as a parameter to a function, it is possible to determine the number of parameters of the closure and the return value type, which means that you almost do not need to construct any inline closures with the full format.
However. You can also use the type of understanding. If you want it to avoid the ambiguity that the reader may Have. This is still worth encouraging.
This sort function example, The purpose of closure is very clear, that is, the order is replaced, and for the reader to be safe if the closure may use a string value, because it is assisting a string array to Sort.
A single-line expression closure can omit the return single-line expression closure to implicitly return the result of a single-line expression by hiding return keyword, such as the sample of the previous version number can be rewritten as:
Reversed = sort (names, {s1, s2 in S1 > S2})
In this Example. The second parameter function type of the sort function understand that the closure must return a Bool type Value. Since the closure function body only includes a single expression (s1 > s2), the expression returns the Bool type Value. Therefore there is no ambiguity, Returnkeyword can be omitted.
The abbreviation Swift itself provides the function of the parameter name shorthand for the inline function, and you can directly refer to the value of the closure by the name of the $0,$1,$2.
Suppose you use a reference abbreviation in a closure expression, you can omit the definition of it in the list of closures, and the type of the corresponding reference abbreviation is judged by the function type. In keyword can be omitted as Well. As a result of this, the closure expression is completely composed of the closure function body:
Reversed = sort (names, {$ > $})
In this example, $ and $ $ represent the first and second String types in a closure.
An operator function is actually another shorter way to write a closure expression in the above Example.
Swift's String type defines an implementation of strings for the Greater-than sign (>). Let it accept as a function two parameters of type String and return a value of type Bool.
This coincides with the type of function that the second parameter of the sort function requires. therefore, you can simply pass a greater than sign, and swift can proactively determine the string function you want to use the Greater-than sign:
Reversed = sort (names, >)
See Operator Functions for a number of other things about operator Expressions.
Trailing closures assume that you need to pass a very long closure expression as the last parameter to the Function. Ability to use trailing closures to enhance the readability of functions.
The Trailing closure is a closure expression that is written outside the function brackets (after), and the function supports calling it as the last Parameter.
Func somefunctionthattakesaclosure (closure: ()) {
function Body part
}
The following is a function call that does not use a trailing closure
Somefunctionthattakesaclosure ({
Closure body part
})
The following is a function call using a trailing closure
Somefunctionthattakesaclosure () {
Closure body part
}
Note: Assuming that the function requires only a single parameter of the closure expression, you can even omit () when you use the trailing Closure. NOTE
In the example above, a string sort that is a parameter of the sort function can be rewritten as:
Reversed = sort (names) {$ > $}
Trailing closures are useful when closures are so long that they cannot be written on a single line. For Example. The Array type of Swift has a map method that gets a closure expression as its unique number of Parameters.
Each element in the array is called once for the closure function and returns the value mapped by the element (which can also be a different type of value). The detailed mapping method and return value type are specified by the Closure.
When supplied to the array closure Function. The map method returns a new array. The array contains the mapped values corresponding to the original array one by ONE.
The following example shows how to use the trailing closure in the map method to convert an array of type Int [16,58,510] to an array that includes the corresponding String type ["onesix", "fiveeight", "Fi Veonezero "]:
Let digitnames = [
0:" Zero ", 1:" one ", 2:" a ", 3:" three ", 4:" four ",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
Let numbers = [+, +, 510]
The above code creates a dictionary of integer numbers to map between their English names. At the same time, an array of integers ready to be converted to a string is Defined.
You can now create a corresponding string version-numbered group by passing a map method that trailing closures to Numbers. It is important to note that calling Numbers.map does not have to include any parentheses after the map, because only one parameter of the closure expression needs to be passed, and the closure expression parameter is written in trailing way:
let strings = Numbers.map {
(var number), String in
var output = ""
While number > 0 {
output = digitnames[number% 10]! + Output
number/=
return output
}//strings Constants are judged as arrays of string types, i.e. string[]
//whose values are ["onesix", "fiveeight", "fiveonezero"]
Map A closure expression was called for each element in the Array. You do not need to specify the type of the input parameter number of the closure, as it can be judged by the type of array to be mapped.
The closure number argument is declared as a variable parameter (for a detailed description of the variable, see constant and Variable Parameters), so it can be changed in the closure function body. The closure expression has a new array type of string that returns a value of type string to indicate that the mapped value is Stored.
The closure expression creates a string and returns each time it is Called. It computes the last digit using the remainder operator (number% 10) and obtains the mapped string using the Digitnames dictionary.
Note: the dictionary digitnames followed by an exclamation mark (!), because the dictionary subscript returns an optional value (optional value), indicating that even if the key does not exist, the lookup fails. In the example above, it guarantees that number% 10 can always be a valid subscript key for a digitnames dictionary. therefore, the exclamation mark can be used to strongly expand (force-unwrap) a String value stored in an optional subscript.
The string obtained from the Digitnames dictionary is added to the front of the output, and the number of the string version number is established in reverse Order. (in the expression number% 10, if number is 16, then 6 is returned.) 58 returns 8,510 returns 0).
The number variable is then divided by 10. Since it is an integer, the remainder of the calculation is Ignored. So 16 became the 1,58 became the 5,510 and became the 51.
The whole process is repeated. Until Number/= 10 is 0. The closure then outputs the String. The map function adds the string to the mapped array.
In the above example, the trailing closure syntax neatly encapsulates the detailed closure function after the Function. Instead of wrapping the entire closure inside the parentheses of the map Function.
Capture (caputure) closures can capture constants or variables in the context in which they are defined.
Even though the original scope for defining these constants and variables no longer exists, closures can still reference and alter these values in the closure function body.
Swift's simplest form of closure is nested functions. This is the function defined in the other function body.
A nested function captures all the arguments of its external function, as well as the constants and variables Defined.
The following example is a function called makeincrementor, which includes a nested function called Incrementor. The nested function Incrementor captures two values from the context, runningtotal and Amount.
The makeincrementor then returns the Incrementor as a closure. Each time Incrementor is Called. It adds the RunningTotal value as an increment of Amount.
Func makeincrementor (forincrement amount:int), Int {
var runningtotal = 0
Func Incrementor (), Int {
RunningTotal + = Amount
Return RunningTotal
}
Return Incrementor
}
The Makeincrementor return type is (), Int.
This means that it returns a Function. Instead of a simple type Value. The function does not accept a parameter on each invocation to return only one value of type Int. For the contents of functions returning other functions, see function Types as return Types.
The Makeincrementor function defines an integer variable runningtotal (initially 0) to store the total number of current Additions. The value is returned by Incrementor.
The
makeincrementor has a parameter of type Int, which is externally named Forincrement and is internally named Amount. Represents the amount RunningTotal will be added each time Incrementor is Called. The
incrementor function is used to run the actual add Operation. This function simply enables RunningTotal to add Amount. and return it.
Suppose we look at this function alone. Will find it looks different:
func incrementor (), Int {
runningtotal + = Amount
return Runningtota L
}
The Incrementor function does not get any arguments, but visits the runningtotal and amount variables in the function body. This is achieved by capturing runningtotal and amount variables that already exist in the body of the function that includes it.
Because the amount variable is not altered, Incrementor actually captures and stores a copy of the variable, which is stored with Incrementor.
However. Since the value of runningtotal is changed every time the function is called, Incrementor captures the reference to the current RunningTotal Variable. Instead of just copying the initial value of the Variable. Capturing a reference guarantees that the makeincrementor will not disappear at the end of the session, and that runningtotal can continue to add the next time the Incrementor function is Run.
Note: Swift Determines whether to capture a reference or copy a Value. You do not need to label amount or runningtotal to declare how you want to use the embedded Incrementor Function. Swift also handles memory management operations for runingtotal variables at the same time. If it is no longer used by the Incrementor function, it will be cleared.
Here is a sample that uses Makeincrementor:
Let Incrementbyten = Makeincrementor (forincrement:10)
The example defines a constant called incrementbyten, which points to a incrementor function that adds 10 per Call. Call this function several times to get the following result:
Incrementbyten ()
The value returned is 10
Incrementbyten ()
The value returned is 20
Incrementbyten ()
The value returned is 30
Let's say You've created a Incrementor. It will have a reference to a separate runningtotal variable that belongs to Itself. In the following example, Incrementbysevne captures a new runningtotal variable that has no relation to the variable captured in Incrementbyten:
Let Incrementbyseven = Makeincrementor (forincrement:7)
Incrementbyseven ()
The value returned is 7
Incrementbyten ()
The value returned is 40
Note: assume that you have a closure assigned to a property of a class Instance. And the closure captures the instance by pointing to the instance or its members, and you create a strong reference ring between the closure and the Instance.
Swift uses a capture list to break such a strong reference ring.
For a lot of other information, please refer to strong Reference Cycles for Closures.
Closures are examples of reference types Above. Incrementbyseven and Incrementbyten are constants, but the closures that these constants point to can still add their captured variable Values. This is because both the function and the closure are reference Types.
Whether you assign a function/closure to a constant or a variable, you are actually setting the value of the constant/variable to the corresponding function/closure reference. In the example above, Incrementbyten a reference to a closure is a constant. Not the contents of the closures Themselves.
This also means that if you assign a closure to two different constants/variables, two values will point to the same closure:
Let Alsoincrementbyten = Incrementbyten
Alsoincrementbyten ()
The value returned is 50
Closures in Swift are similar to those in the blocks in C and Objective-c and Lambdas in other programming languages.