Closures are self-contained blocks of function code that can be passed around and used in code. Closures in Swift are similar to code blocks in C and Objective-C and anonymous functions in other programming languages.

Closures can capture and store any defined constant and variable references within the context. These constants and variables are named Closures because of their closure. Swift has memory management for all references you can capture.

Closures are essentially code blocks, which are upgraded versions of functions. Functions are named, reusable code blocks, and closures are anonymous code blocks that are more flexible than functions.

1. Closure Expression -Closure Expression

Closure expressions contain parameters, return values, and function body code. Note The parameters cannot have default values.

{(parameter list) -> Return value type in function body code}Copy the code

2. Shorthand for closure expressions

let names = ["block1","block2","block3"] var reversedName = name.sorted(by: {(s1: String,s2: String) -> Bool in return s1 > s2})Copy the code

Simplify:

Swift can infer parameter types and return value types, so it can omit types. A single expression can be written without a return. Swift can abbreviate the actual parameter name, which can be 0,0,0,1.

Trailing closure: If the last argument to a function is a closure, the closure can be written outside the parameter parentheses. To improve the readability of the function.

If the closure expression is the only argument to the function, then the parentheses can also be omitted.

var reversedName = name.sorted{ > }
Copy the code

3. Closure definition and value capture

  • A function combined with its captured variable and constant environment is called a closure.
  • Closures are typically functions defined inside functions.
  • Closures typically capture local variables and constants of the outer function.
Typealias Sum = (Int) -> Int getSum() -> Fn {var num = 0; typeAlias Sum = (Int) -> Int getSum() -> Fn {var num = 0; Func add(_ I: Int) -> Int {num += I return num} return add} /* Fn has 16 bytes, the first 8 bytes are the address of the add function, and the last 8 bytes are the address of the heap  fn = getSum() /*1>. After executing the above line, that is, after calling the getFn method. GetSum (num); getSum (num); getSum (num); getSum (num); Fn stores the address of the add function, and the num used in the add method is stored in the heap (value capture), thus extending the life of num so that it is not destroyed after getSum is executed. If num is a global variable, then num is stored in the global data area and num is not stored in the heap. */ print(fn(1)) // print(fn(5)) // print(6) * /Copy the code

Conclusion of analogy: Think of a closure as an instance object of a class

  • 1>. Is stored in heap space.
  • 2>. The captured local variables, constants, act as members of the object (storing attributes), in heap memory of course.
  • 3>. The functions that make up the closure are equivalent to the methods defined inside the class (the Add method above).

4. Escaping closure, escaping closure

  • Non-escape closure, escape closure is when the closure is passed to a function as an actual parameter.
  • Non-escaping closures: Closure calls occur before the end of a function, and the closure calls are in function scope.
  • Escape closure: It is possible for a closure to be called after the function has finished, and the call escapes the scope of the function. Escaping is needed to modify closures to allow escape. It is used for network requests.

Note: Letting the closure escape means that self must be explicitly referenced in the closure.

Typealias FunBlock = () -> () // Non-escape closure func test(_ fn: Test {print(3)} // escape closure var gFn: FunBlock? // Instead of calling the closure fn in the function scope, we assigned the function to a variable called func test2(_ fn: @escaping FunBlock) {gFn = fn}. @escaping FunBlock) { DispatchQueue.global().async { fn() } }Copy the code

5. Automatic closures

  • An automatic closure is an expression that automatically converts to a closure.
  • Autoclosure only supports arguments in () -> T format.
  • Autoclosure does not only support the last parameter.

Note: Where autoclosure is used, this value is deferred.

func justFun(_ condition: @autoclosure ()->Bool, _ message: @autoclosure ()-> String) { return condition() ? Message () : "no String"} // Call justFun(Number == 5,"number = 5") // Autoclosure automatically wraps number == 5 as {number == 5}Copy the code

Use of escape closures and automatic closures

var names = ["just","kiw","jket","lku"] var customeFunsList: [() -> String] = [] // The closure is not called at this time, so @escaping func customeFuns(customeFun: @autoClosure @escaping () -> String) {customeFunsList. Append (provider)} @autoClosure () -> String) {customeFunsList. Name. Count = 4 collectCustomerProviders(customeFun: CustomeFunslist. remove(at: // Now names.count = 4 collectCustomerProviders(customeFun: customeFunsList. Remove (at: 0)) for customeFun in customeFunsList {print(customeFun())Copy the code