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