This is the 8th day of my participation in the More text Challenge. For details, see more text Challenge
closure
- Closures are independent blocks of functional code that can be passed and used in code
- Closures and
block
The contrast of- Closures in SWIFT are similar to blocks in OC
- A closure in SWIFT is a special function in OC
block
Is an anonymous function - Closures and
block
Are often used for callbacks - Block expression
Type: Return value type (^block name)(parameter to block) Return value (^block name)(parameter list) = ^(parameter list){// Execute the code }; NSString* (^blockName)(NSString *str) = ^(NSString *str){ return str; }; blockName(@"block") Copy the code
- Closure expression
Type :(parameter)->(return value type) closure name = {(parameter list)->returnThe return valuein // Execute the code } let closure = { (str:String) - >String in return str } closure("closure") Copy the code
The closure type
- No parameter No return value
let closure = {()->Void in print("closure") } closure() Copy the code
- Yes Parameter No return value
let closure = {(str:String) -> Void in print(str) } closure("closure") Copy the code
- No parameter has a return value
let closure = {() -> String in return "closure" } closure() Copy the code
- There are parameters and return values
let closure = { (str:String) - >String in return str } closure("closure") Copy the code
Closure expression
The following example shows the definition and syntax optimization of the sorted(by:) method by using several iterations. Each iteration describes the same functionality in a more concise way
-
Function processing
The sorted(by:) method accepts a closure that needs to pass in two values of the same type as the array elements and return a Boolean value to sort. The sort closure type must be :(Int, Int) -> Bool
let numbers = [1.9.2.8.3.7.4.6]; let numArr = numbers.sorted(by: callback) func callback(_ numA:Int, _ numB:Int) -> Bool { return numA < numB } print(numArr) log: [1.2.3.4.6.7.8.9] Copy the code
-
Handled by closure expressions
The inlined closure argument and return value type declarations are the same as the callback(_:_:) function type declarations
let numbers = [1.9.2.8.3.7.4.6]; let numArr = numbers.sorted { (numA:Int, numB:Int) -> Bool in return numA < numB } print (numArr) log: [1.2.3.4.6.7.8.9] Copy the code
-
Infer types from context
The sorted(by:) method is called with an array of ints, so its arguments must be functions of type (Int, Int) -> Bool. Since all types can be inferred correctly, the return arrow (->) and the parentheses surrounding the arguments can also be omitted
let numbers = [1.9.2.8.3.7.4.6]; let numArr = numbers.sorted { numA,numB in return numA < numB } print(numArr) log [1.2.3.4.6.7.8.9] Copy the code
-
Single-expression closures return implicitly
The sorted(by:) method argument type specifies that the closure must return a value of type Bool, because the closure body contains only a single expression (s1 > s2) that returns a value of type Bool, so there is no ambiguity here and the return keyword can be omitted
let numbers = [1.9.2.8.3.7.4.6]; let numArr = numbers.sorted { numA,numB in numA < numB } print(numArr) log: [1.2.3.4.6.7.8.9] Copy the code
-
Parameter name abbreviation
You can call the arguments of the closure directly with $0,$1,$2, and so on. If you use an argument name abbreviation in a closure expression, you can omit the argument list from the closure definition, and the type of the corresponding argument name abbreviation is inferred from the function type. The in keyword can also be omitted because the closure expression consists entirely of the body of the closure function
let numbers = [1.9.2.8.3.7.4.6]; let numArr = numbers.sorted {$0The < $1} print(numArr) log: [1.2.3.4.6.7.8.9] Copy the code
-
Operator method
Swift’s Int type defines an implementation of the greater-than sign (>) as a function that takes two ints and returns a Bool. This, in turn, matches the function type required for the argument to the sorted(by:) method. Therefore, you can simply pass a greater-than sign
let numbers = [1.9.2.8.3.7.4.6]; let numArr = numbers.sorted(by: <) print(numArr) log: [1.2.3.4.6.7.8.9] Copy the code
Following the closure
An anonymous closure is passed as an argument to an ordinary function
-
If the closure is the last argument to the function, then the closure is called after parentheses ()
func sayHi(str1:String.str2:String.closure: (String.String) - >String) - >String{ return closure(str1,str2); } let message = sayHi(str1: "hello", str2: "world") { (str1:String.str2:String) - > (String) in return str1 + "" + str2 } print(message) log: hello world Copy the code
-
If the function has only one argument and is a closure, the parenthesis () can be called without being written
func sayHi(closure:(String)->())-> Void { print("There's only one parameter.") closure("hello world") } sayHi { (str:String) in print(str) } log: Only takes one argument hello worldCopy the code
Value capture
Closures can capture constants or variables in the context in which they are defined. Even if the original scope in which these constants and variables were defined no longer exists, the closure can still refer to and modify these values within the closure function body.
func add(num:Int) -> ()->Int {
var value = 0
func result() -> Int{
value += num
return value
}
/* There is a function called add, which contains a nested function called result. The nested function result() captures two values from the context. After the values are captured by value and num, add returns result as a closure each time result is called. It increments value */ by num
return result
}
Copy the code
-
A nested function captures all the parameters of its external function, as well as defined constants and variables, and ensures that the values captured are still present the next time the function is executed
func add(num:Int) -> ()->Int { var value = 0 func result() -> Int{ value += num return value } return result } let result = add(num: 10) print(result()) / / 10 print(result()) / / 20 print(result()) / / 30 Copy the code
-
Variables in the same method are bound to their own variables
func add(num:Int) -> ()->Int { var value = 0 func result() -> Int{ value += num return value } return result } // If you create another result1, it will have its own reference to a new, independent value variable let result1 = add(num: 10) print(result1()) / / 10 // Calling result again will add its own value variable, which has no relation to the variable captured in result1 print(result()) / / 40 Copy the code
Closures are reference types
-
Both functions and closures are reference types
Assigning a function or closure to a constant or variable is really setting the value of the constant or variable to a reference to the corresponding function or closure
// Both constants or variables refer to the same closure let method = result Copy the code
Escape a closure
- A closure passed to a function that is not called until after the function has finished executing is called an escape closure. In general terms, you do not use closures within the current method, but outside the method
- When you define a function as an escaping closure, you simply need to preceded the argument name with @escaping to indicate that the closure will allow “escaping” out of the function
- Mark a closure as
@escaping
Means you must explicitly reference it in the closureself
var result: ()->Void = {} var str = "" func showA(closure: @escaping () -> Void) { result = closure } func showB(closure: () -> Void) { closure() } func doSomething() { showA {str = "I am the escape closure."} showB {str = "I'm a normal closure."} } doSomething() print(str) // I'm a normal closure result() print(str) // I am the escaping closure Copy the code
The escaping closure is executed after the function has executed, so the code ends with “I am the escaping closure.”
Automatic closure
-
Automatic closure: Automatically creates a closure to wrap an expression. This closure takes no arguments and, when called, returns the value of the expression wrapped in the closure
-
Automatic closures allow you to delay evaluation because the code snippet will not be executed until you call the closure
-
This convenience syntax allows you to omit the closure curly braces and replace the explicit closure with a plain expression
var arr = ["a"."b"."c"] print(arr.count) / / 3 let closure = { arr.remove(at: 0) } print(arr.count) / / 3 print(closure()) //a print(arr.count) / / 2 Copy the code
-
You can also delay evaluation when passing closures as arguments to a function
The function takes an argument of an explicit closure type
func delete(closure: ()->String){ print(closure()) } var arr = ["a"."b"."c"] delete(closure:{arr.remove(at: 0)}) log: a Copy the code
Receive an autoclosure by marking the argument @autoclosure. This function accepts a String argument instead of a closure
func delete(closure: @autoclosure ()-> String){ print(closure()) } var arr = ["a"."b"."c"] delete(closure:arr.remove(at: 0)) log: a Copy the code