Contents of this article:
- closure
- Following the closure
- Escape a closure
- Automatic closure
- A circular reference
closure
- Global functions: have names and do not capture any values;
- Nested functions: have names that capture values from their enclosing functions;
- Closure expressions: nameless, capturing values from adjacent blocks;
Closure expression
{(parameter) -> Return valueinExpression}Copy the code
Omit return value:
{(parameter)inExpression}Copy the code
Arguments and return values are omitted:
{expression}Copy the code
Closure type variable
Closure that declares the variable closure:
let closure = {(a:Int,b:Int) -> Int in
returnA + b} closure (2, 3)Copy the code
Following the closure
When the last argument to a function is a closure, it can be written as a trailing closure, that is, the closure argument tag can be omitted and the closure expression can be written after ().
Function the add:
func add(closure:() -> Void){
}
Copy the code
Call the function add without the trailing closure form: ‘
add(closure: {
})
Copy the code
Call the function add, using the trailing closure form, and omit the argument tag closure:
add() {}Copy the code
When the closure is the only argument to a function, you can even omit () :
add {
}
Copy the code
Escape a closure
Add the @escaping keyword before closures.
A closure passed to a function as an argument and executed after the function returns is said to escape from the function. Typically used in asynchronous functions that return as soon as the asynchronous operation starts, but the closure is not called until the asynchronous operation ends.
The escape closure function is written so that the closure can be called after the function returns:
var closureArray:[() -> Void] = []
func escapingClosure(closure: @escaping () -> Void) {
closureArray.append(closure)
}
Copy the code
Non-escape closure:
func nonEscapingClosure(closure: () -> Void) {
closure()
}
Copy the code
Call the non-escape closure function with an x value of 100:
var x = 10
nonEscapingClosure {
x = 100
}
print(x) // now x is 100Copy the code
The closure function is called, and x is still 100:
escapingClosure {
x = 200
}
print(x) // Now x is still 100Copy the code
Because the closure escaped, the closure was not executed, so x=200 in the code block was not executed. The escape closure is called with the x value changed to 200:
closureArray.first? (a)print// Now x is 200Copy the code
Automatic closure
Add the @autoclosure keyword before the closure.
An automatic closure automatically wraps an expression as a function parameter into a closure.
Let’s start with a function call that doesn’t use automatic closures:
func isTure(predicate: () -> Bool) {
if predicate() {
print("is ture")}else{
print("is false")}}Copy the code
Call:
isTure { () -> Bool in
return2 > 1}Copy the code
Consider the call to a function that uses automatic closures:
func isTure(predicate: @autoclosure () -> Bool) {
if predicate() {
print("is ture")}else{
print("is false")}}Copy the code
Call:
isTure(predicate: 2>1)
Copy the code
Automatic closures look nice syntactically.
A circular reference
Assigning a closure to a property of a class instance that uses the instance creates a strong reference loop, creating a circular reference.
Resolving circular references
Define a capture list:
Closures have parameters and return types, and place the capture list before them:
var someClosure = {
[weak self] (index:Int) -> String in
}
Copy the code
The closure has no arguments and no return types. Place the capture list and keyword in at the beginning of the closure:
var someClosure = {
[weak self] in
}
Copy the code
The resources
SwiftGG