blog
blog copied to clipboard
swift4 语法备忘- Closure
Closures
Closures can capture and store references to any constants and variables from the context in which they are defined.
Three Form
-
Global functions
are closures that have a name and do not capture any values. -
Nested functions
are closures that have a name and can capture values from their enclosing function -
Closure expressions
are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.
Swift closures enhancement
- Inferring parameter and return value types from context
- Implicit returns from single-expression closures
- Shorthand argument names
- Trailing closure syntax
Closure Expression Syntax
General Form of Closure
{ (parameters) -> return type in
statements
}
Trailing Closures
A trailing closure is written after the function call’s parentheses, even though it is still an argument to the function. When you use the trailing closure syntax, you don’t write the argument label for the closure as part of the function call.
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
// closure's body goes here
})
// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}
closure demo
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
var reversedNames = names.sorted(by: backward)
// reversedNames is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
// with closure systax
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
// shorten with single line version
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )
// shorten with Inferring Type From Context version
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )
// shorten with Implicit Returns from Single-Expression
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
// shorten with Shorthand Argument Names
reversedNames = names.sorted(by: { $0 > $1 } )
// shorten with Operator Methods
reversedNames = names.sorted(by: >)
// shorten with Trailing Closures
reversedNames = names.sorted() { $0 > $1 }
reversedNames = names.sorted { $0 > $1 } // only argument can omit parentheses()
Capturing Values
A closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.
In swift, A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function.
@escaping
closure means it needs to refer to self explicitly
func makeAnIncrement(_ delta: Int) -> () -> Int {
var startValue: Int = 0;
func Inc() -> Int {
startValue += delta;
return startValue;
}
return Inc
}
let Ten = makeAnIncrement(10);
_ = Ten();
_ = Ten();
let t = Ten();
print(t) // 30
let Twn = makeAnIncrement(20);
_ = Twn();
_ = Twn();
let x = Twn();
print(x) // 60
Closures Are Reference Types
Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure.
Escaping Closures
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write
@escaping
before the parameter’s type to indicate that the closure is allowed to escape.
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
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)
// Prints "200"
completionHandlers.first?()
print(instance.x)
// Prints "100"
Autoclosures
An
autoclosure
is a closure that is automatically created to wrap an expression that’s being passed as an argument to a function. It doesn’t take any arguments, and when it’s called, it returns the value of the expression that’s wrapped inside of it. This syntactic convenience lets you omit braces around a function’s parameter by writing a normal expression instead of an explicit closure.
An autoclosure lets you delay evaluation, because the code inside isn’t run until you call the closure
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
// Prints "Now serving Alex!"
// autoclosure version
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
// Prints "Now serving Ewa!"