Closures are self-contained function code blocks that can be passed and used in code, and closures in Swift are similar to those in C and OC (blocks) and anonymous functions in other programming languages
Closures can capture and store references to any constants and variables in their context, called Package constants and variables, and Swift manages all of the memory operations involved in the capture process
The global and nested functions described in the ' Functions ' section are actually special closures, and closures take one of the following three forms:
1: A global function is a closure that has a name but does not capture any job
2: A nested function is a closure that has a name and can capture the values in its enclosing function domain
3: A closure expression is an anonymous closure that uses lightweight syntax to capture variables or constant values in its context
Swift's closure expressions have a concise style and encourage syntax optimization in common scenarios, with the main optimizations as follows:
1: Use context to infer parameters and return value types
2: Implicitly returns a single-expression closure, that is, a single-expression closure can omit the return keyword
3: Parameter name abbreviation
4: Trailing closure syntax
Closed-Packet expression
' Nested functions ' is a convenient way to name and define self-contained code modules in more complex functions, but sometimes it is useful to write small, well-defined and named class function structures, especially if you are dealing with functions and need to use other functions as arguments to the function.
' Closure expression ' is a way to construct an inline closure using concise syntax, and the closure expression provides some syntax optimizations that make it straightforward to write closures, and the following example of a closure expression shows the sorted by using several iterations: method definition and syntax optimization, each iteration describes the same functionality in a more concise way
Sorted method
The SWIFT standard Library provides a method named sorted (by:) that sorts the values in the known type array according to the closure function you provide for sorting, once the sort is complete, sorted (by:) The sorted method returns a new array with the same size as the original array, with elements of the same type, and the elements are sorted correctly, and the original array will not be replaced by: Method modification
The following example of a closure expression uses sorted (by:) method to sort an array of type string in alphabetical order, the following is the initial array
Let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
The sorted (by:) method accepts a closure, and the closure function needs to pass in two values that are the same as the array element type, and returns a Boolean value that indicates whether the first parameter passed in after the sort ends before or after the second argument, and if the first parameter value appears before the second parameter value, The sort closure function needs to return true, and vice versa to return False
The change example sorts an array of type string, so the sort closure function type needs to be (string, string)-Bool.
One way to provide a sort closure function is to compose a common function that meets its type requirements and use it as a sorted (by:) The parameters of the method are passed in:
Func Backward (_ S1:string,_ s2:string), bool{
return S1 < S2
}
var reversednames = names.sorted (By:backward (_:_:))
Print (Reversednames)
Closure-expression Syntax
The closure expression syntax is a general form of
{(parameters)-ReturnType in
Statements
// }
A closure expression can be a in-out parameter, but you cannot set a default value, or you can make a variable parameter to the appliance name (but if the variable parameter is not in the last one in the argument list, the editor will error when the call is closed), and the tuple can also be used as a parameter and a return value
The following example shows the code for the version of the closure expression corresponding to the previous backward (_:_:) function
Reversednames = names.sorted (by: {(s1:string,s2:string)-Bool in
return s1 > S2
})
It is important to note that the inline closure parameter and the return value type declaration are associated with backward (_:_:). The function type declaration is the same, in both of these ways (s1:sreing, s2:string), Bool, however, in an inline closure expression, the function and return values are written in curly braces, not outside the curly braces
The function body portion of the closure is introduced by the keyword ' in ', which means that the closure parameter and the return value type definition have been completed and the closure function body is about to begin.
Because the function part of the closure is so short that it can be rewritten into a single line of code
In the example, sorted (by:) The overall invocation of the method remains unchanged, and a pair of parentheses still wraps the entire parameter of the method, however, the parameter now becomes an inline closure.
Infer types based on context
Because the sort closure function is as sorted (by:) The parameters of the method are passed in, and swift can infer the type of the return value of its argument, sorted (by:) The String,string method is called by a string array, so its argument must be a function of type Bool, which means that the type (string, string) and bool do not need to be part of the closure expression because all types can be inferred correctly. The return Arrows (-) and the parentheses around the parameters can also be omitted
Reversednames = names.sorted (by: {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 or method, it is always possible to infer the parameter and return value type of the closure, which means that you hardly need to construct the inline closure with the full format when the closure is a parameter of a function or method
However, you can still explicitly write this complete form of closure, if the complete format of closures can improve the code formation, we encourage the use of a complete format of closures, and in the sorted (by:) Method Example, it is obvious that the purpose of closure is to sort, Since this closure is intended to handle the ordering of character arrays, the reader can infer that the closure is used for string processing
Single-expression closed Baoyin return
A single-line expression can implicitly return the result of an expression by omitting the return keyword.
Reversednames = names.sorted (by: {s1,s2 in S1 > s2})
Parameter name abbreviation
Swift automatically provides the parameter name abbreviation for inline closures, which you can call directly through the parameters of the closure in the order of $, $, $, and so on.
If you use a parameter name abbreviation in a closure expression, you can omit the argument list in the closure definition, and the type that corresponds to the parameter name abbreviation is inferred from the function type, and the In keyword is also omitted because the closure expression is completely composed of the closure function body
Reversednames = names.sorted (by: {$ > $})
In this example, the $ $ and $ $ represent the first and the iterated String arguments in the closure
Operator methods
In fact, there is a shorter way to write the closure expression in the above example, Swift's string type defines the greater than sign (>) of the implementation of the strings, as a function to accept two string arguments and return the value of type Bool, which is exactly the same as sorted (by:) The parameters of the method require the function type to match, so you can simply pass a greater than sign (>) Swift can be automatically inferred when you want to use the greater-than-sign string function to implement
Reversednames = names.sorted (by: >)
Trailing closures
If you need to pass a long closure expression as the last argument to the function, you can use ' trailing closure ' to enhance the readability of the function.
' Trailing closure ' is a closure expression that is written after the function bracket, and the function supports calling it as the last argument, and you don't have to write out his parameter tag when using a trailing closure
Func somefunctionthantakesaclosure (Closure: ()->void) {
}
The following is a function call that does not use a trailing closure
Somefunctionthantakesaclosure (Closure: {
Closure body
})
The following is a function call using a trailing closure
Somefunctionthantakesaclosure () {
Closure body
}
In the closure expression Syntax section as sorted (by:) The string sort closures for method parameters can be rewritten as:
Reversednames = names.sorted () {
$ > $
}
Trailing closures become very important when closures are so long that they cannot be written on a single line.
For a chestnut: Swift's Array type has a map (_:) method, which gets a closure expression as its unique parameter, which is called once for each element in the array and returns the value mapped by the element, with the specific mapping and return value types specified by the closure
When a closure supplied to an array is applied to each array element, map (_:) method returns a new array that contains the mapped value corresponding to element one by one of the original array
The following example:
Let digitnames = [
0: "Zero", 1: "One", 2: "One", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
Let numbers = [16,58,510,1468415]
You can now pass a trailing closure to the numbers array, map (_:) method to create the corresponding string version array
Let strings = Numbers.map {(number:int), String in
var number = number
var output = ""
repeat{
Output = digitnames[number% 10]! + Output
Number/= 10
}while Number > 0
Return output
}
Print (strings)
Map (_:) Once a closure expression is called for each element in the array, you do not need to specify the type of the input parameter number for the closure, because the type of the array to be mapped can be inferred.
In this example, the value of the local variable number is obtained by the # parameter in the closure, so it can be modified in the body of the closure function (the closure or function arguments are constants), and the closure expression specifies that the return type is string, indicating that the type of the new array that stores the mappings is string
The closure expression creates an output string and returns each time it is called, using the remainder operator (%) Computes the last digit and obtains the mapped string using the Digitnames dictionary, which can be used to create a string representation of any positive integer
Note: The dictionary digitnames followed by an exclamation mark (!), because the dictionary subscript returns an optional value (optional value), indicating that the key does not exist or will fail to find, in the example above, because you can determine that ' number% 10 ' is always DIGITN Ames a valid subscript for a dictionary, so an exclamation mark can be used to strongly parse the value of a String stored in the return value of an optional type of subscript
In the example above, with the trailing closure syntax, the elegant code
Value capture
Closures can capture constants and variables in the context in which they are defined, even if the original scope for defining those constants and variables no longer exists, closures can still reference and modify these values in the early closure function body
In Swift, the simplest form of closure that can capture a value is a nested function, which is a function defined in the function body of another function, which captures all parameters of its external function and defines constants and variables
Func makeincrementer (Forincrementer amount:int), Int {
var runningtotal = 0
Func Incrementer (), Int {
RunningTotal + = Amount
Return RunningTotal
}
Return Incrementer
}
For example, there is a function called Makeincrementer, which contains a nested function called Incrementer. The nested function Incermenter () captures two values from the context, runningtotal and amount, after capturing these values, Makeincrementer returns Incrementer as a closure, and each time incrementer is called, it Increases the value of runningtotal as an increment of amount amount.
Note: In order to optimize, if a value is not changed by a closure, or does not change after the closure is created, Swift may instead capture and save a copy of the value, and Swift will also be responsible for the management of all the contents of the captured value, including releasing the non-required variables
Here is an example of using Makeincrementer:
Let Incrementbyten = Makeincrementer (forincrementer:10)
This example defines a constant called Incrementbyten. The constant points to a incrementer () function that increments its runningtotal variable by 10 per call.
Print (Incrementbyten ())
Print (Incrementbyten ())
Print (Incrementbyten ())
If you create another incrementer, he will have his own reference, pointing to a brand-new, independent runningtotal variable:
Let Incrementbyseven = Makeincrementer (forincrementer:7)
Print (Incrementbyseven ())
Calling the original Incrementbyten () again will continue to add its own runningtotal variable, which is not associated with the variable captured in Incrementbyseven ()
Print (Incrementbyten ())
Closures are reference types
In the above example, Incrementbyseven and Incrementbyten are constants, but the closures that point to these constants can still increase the value of the variable they are capturing because both the function and the closure are reference types
Whether you assign a function or a closure to a constant or a variable, you are actually referring to the value of the constant or variable set to the corresponding function or closure.
Escape Closure Package
When a closure is passed as a parameter to a function, but the closure is executed after the function is returned, we call the closure escaping from the function. When you define a function that accepts a closure as a parameter, you can label the @escaoing before the parameter name, which is used to kill the closure to allow ' escape ' out of this function.
One way to make the closure ' escape ' function is to keep this closure in a variable defined by a function, for a chestnut, many functions that initiate an asynchronous operation accept a closure parameter as completion handler. Such functions return immediately after the asynchronous operation begins, but the closure is not called until the end of the asynchronous, in which case the closure needs to ' escape ' the function because the closure needs to be called after the function returns
var completionhandlers: [()-Void] = []
Func somefunctionwithescapingclosure (Completionhandler: @escaping (), Void) {
Completionhandlers.append (Completionhandler)
}
Somefunctionwithescapingclosure (_:) The function takes a closure as an argument, and the closure is added to an array defined outside the function, and if you do not mark the function as @escaping, a compilation error is returned
Marking a closure as @escaping means that you must explicitly refer to self in the closure. For example, in the following code, pass to Somefunctionwithescapingclosure (_:) The closure in the is an escape closure, which means that it needs to explicitly refer to self. Relative, passed to Somefunctionwithnonescapingclosure (_:) The closure in is a non-escape closure, which means that it can implicitly refer to self.
Func somefunctionwithnonescapingclosure (Closure: ()-Void) {
Closure ()
}
Class SomeClass {
var x = 10
Func dosomething () {
somefunctionwithescapingclosure {self.x = 100}
somefunctionwithnonescapingclosure {x = 200}
}
}
Let instance = SomeClass ()
Instance.dosomething ()
Print (instance.x)
Print out "200"
Completionhandlers.first? ()
Print (instance.x)
Print out "100"
Auto-closing Package
' Auto-closure ' is an auto-created closure used to wrap an expression passed to a function as a parameter, which does not accept any parameters, and when it is called, returns the value of the expression being wrapped in it, which allows you to omit the closing curly braces and use a common expression instead of the displayed closure
We often invoke functions that employ automatic closures, but seldom implement such functions. For instance, assert (Condition:message:file:line:) The function accepts the auto-closure as its condition parameter and the message parameter, its condition parameter is evaluated only in debug mode, and its message parameter is evaluated only when the condition parameter is false.
Automatic closures allow you to delay the evaluation because the code snippet will not be executed until you call the closure. Latency evaluation is useful for code that has side effects (Side Effect) and high computational costs because it allows you to control the timing of code execution. The following code shows how the closure is evaluated for delay.
var customersinline = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
Print (Customersinline.count)
Print out "5"
Let Customerprovider = {customersinline.remove (at:0)}
Print (Customersinline.count)
Print out "5"
Print ("Now Serving \ (Customerprovider ())!")
Prints "Now Serving chris!"
Print (Customersinline.count)
Print out "4"
Although the first element of Customersinline is removed in the code of the closure, the element is not removed until the closure is called. If the closure is never called, then the expression inside the closure will never be executed, which means that the elements in the list are never removed.
Note: The type of Customerprovider is not a string, but a () string, a function with no parameters and a return value of string, and you can get the same delay evaluation behavior when you pass the closure as an argument to the function
Func Serve (Customer Customerprovider: () String) {
Print ("Now Serving \ (Customerprovider ())!")
}
Serve (Customer: {customersinline.remove (at:0)})
Swift Learning-08--Closures