Closures are self-contained blocks of functional code that can be used in code or used to pass values as parameters. Closures in Swift are similar to C, OC blocks, lambdas in other programming languages (such as C #), function nesting in javascript, etc. Closures can capture and store references to any constants and variables defined in the context. This is called variables and self-closing of variables, so closures also handle the memory management of all captured references. Global functions and nested functions are actually special closures. The form of the closure is:
(1) Global functions are closures that have names but cannot capture any values.
(2) Nested functions are closures and have names, which can also capture the values inside the closed function.
(3) Closure expressions are all unnamed closures. Using lightweight syntax, values can be captured according to the context.
There are many optimizations for closures in Swift:
(1) Infer parameter and return value types based on context
(2) Implicit return from a single-line expression closure (that is, the closure body has only one line of code, and return can be omitted)
(3) You can use simplified parameter names, such as $ 0, $ 1 (starting from 0, indicating the i-th parameter ...)
(4) Provided trailing closure syntax
2. Usage examples (The examples listed here are summarized from the book "The Swift Programming Language")
The following uses the sort method in the Swift standard library to simplify the closure step by step.
sort function requires two parameters
Parameter one: array
Parameter 2: A closure: with two parameters, the type of these two parameters is the same as the type of the elements in the array, the return value is Bool
Array:
var names = ["Swift", "Arial", "Soga", "Donary"]
The first way: using functions
func backwards (firstString: String, secondString: String)-> Bool {
return firstString> secondString // sort in descending order
}
transfer:
sort (& names, backwards)
The use of this method is equivalent to the callback backward method.
The second way: using closures
The complete closure is written with a parameter list and a return value in curly brackets, and the keyword in is used to indicate the beginning of the closure body.
(1) (firstString: String, secondString: String) Closure parameter list
(2)-> Bool indicates that the closure return value type is Bool
(3) the in keyword indicates the start of the closure body
sort (& names, {(firstString: String, secondString: String)-> Bool in
return firstString> secondString
})
You can further simplify the writing here because the closure code is relatively short and can be written on one line
sort (& names, {(firstString: String, secondString: String)-> Bool in return firstString> secondString})
The following further simplifies the writing: the type is automatically inferred according to the environment context, the parameter list does not specify the type, and the return value type is not specified, because swift can infer from the context that the type of firstString and secondString will be the type of the names array element , And the return value type will be obtained according to the result of the return statement
sort (& names, {firstString, secondString in return firstString> secondString})
Further simplified: implicit return (single-line statement closure), because the closure body has only one line of code, you can omit return
sort (& names, {firstString, secondString in firstString> secondString})
Further simplification: using simplified parameter names ($ i, i = 0,1,2 ... starting from 0), Swift will infer that the closure requires two parameters, the type is the same as the elements of the names array
sort (& names, {$ 0> $ 1})
The simplest way: using operators
sort (& names,>)
Trailing Closures
If the function requires a closure parameter as the parameter, and this parameter is the last parameter, and the closure expression is long, it is useful to use trailing closures. Trailing closures can be placed outside the function parameter list, ie outside the parentheses. It is to extract the closure that was originally in the parameter list to the back of the function and write it, so it is easy to read and use.
1. Still using the sort method as an example, the normal closure is written as follows:
sort (& names, {(firstString: String, secondString: String)-> Bool in
return firstString> secondString
})
However, it can be found that the second parameter in the sort function is very long and not easy to read. At this time, we can use a trailing closure to modify it. The code is as follows:
sort (& names) {
(firstString, secondString)-> Bool in
return firstString> secondString
}
2. Map method example, output a string corresponding to an array
var numbers = [1,2,3]
let strings = numbers.map ({
(var number)-> String in
var output = ""
while number> 0 {
output = String (number% 10) + output
number / = 10
}
return output
})
Note that map is a method and its parameters have only one closure, so we can also use the form of trailing closures, written as follows
var numbers = [1,2,3]
let strings = numbers.map () {
(var number)-> String in
var output = ""
while number> 0 {
output = String (number% 10) + output
number / = 10
}
return output
}
The map function does not have any other parameters, only a closure parameter, so the "()" after the map can be omitted, and the final trailing closure can be written as
var numbers = [1,2,3]
let strings = numbers.map {
(var number)-> String in
var output = ""
while number> 0 {
output = String (number% 10) + output
number / = 10
}
return output
}
Fourth, the captured value
Closures can capture defined constants and variables based on the context of the environment. Closures can reference and modify these captured constants and variables. The simplest form of closures in Swift is nested functions.
func increment (#amount: Int)-> (()-> Int) {
var total = 0
func incrementAmount ()-> Int {
total + = amount // total is a variable inside the external function body, which can be captured here
return total
}
return incrementAmount // returns a nested function (closed)
}
Closures are reference types, so declarationByTen declared as a constant can also modify the total
let incrementByTen = increment (amount: 10)
incrementByTen () // return 10, incrementByTen is a closure
// Here is no change to the reference to increment, so the previous value will be saved
incrementByTen () // return 20
incrementByTen () // return 30
Five, the circular reference problem of closures
In the Objective-C era, when using blocks, you have to consider the issue of block circular references. The measures taken at that time were to weaken the side of circular references, such as:
__weak typeof (self) wSelf = self;
The same problem exists in closures in Swift. In fact, the general idea is the same, we can use the unowned keyword.
Example: Convert the attributes of an object into XML form:
class HTMLElement {
var name: String
var text: String?
init (name: String, text: String?) {
self.name = name
self.text = text
}
lazy var asHtml: ()-> String = {
[unowned self] in
if let text = self.text {
return "<\ (self.name)> \ (self.text) </ \ (self.name)>"
} else {
return "<\ (self.name)>"
}
}
}
var html = HTMLElement (name: "Node", text: "Jack")
html.asHtml ()
In the above code, self has a strong reference to the asHtml closure property, and asHtml has a strong reference to self, so we can use [unowned self] to "weaken" self. This removes circular references.
Six, examples of the use of closures in the actual UIKit environment
The UI interface is as follows:
The function is simple
1. The gray View above is a custom View (TestView.swift), which contains a text input box and a "GO" button.
2. The latter section is the controller's View (ViewController.swift), which contains a testLabel.
3. Click the "GO" button to call back the content in the text box to the Label display in ViewController.swift
TestView.swift code:
class TestView: UIView {
required init (coder aDecoder: NSCoder) {
fatalError ("init (coder :) has not been implemented")
}
}
In the code, I define a testClosure closure property, and its method will be called when the "GO" button is clicked. Notice the definition of closures
var testClosure: ((str1: String)-> Void)?
It is nullable because the assignment of the testClosure closure property is not necessarily done in the controller ViewController.swift. So when calling the closure, it is written as
self.testClosure? (str1: self.textField1.text)
And the code assigned in ViewController.swift is as follows:
class ViewController: UIViewController {
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.