first, the basic concept
Closures (Closures) are self-contained functional code blocks that can be used in code or used as parameter values. Closures in Swift are similar to lambda in C, OC, and other programming languages (such as C #), function nesting in JavaScript, and so on. Blocks.
Closures are capable of capturing and storing references to whatever constants and variables defined in the context.
This is called self-containment of variables and variables, so closures also handle the memory management of all captured references.
global functions and nested functions are, in fact, special closures.
Closures are in the form of:
(1) Global functions are closures. Have a name but cannot capture whatever value.
(2) Nested functions are closures. With a name, you can also capture the value within the enclosing function.
(3) The closure expressions are anonymous closures, using lightweight syntax. Ability to capture values based on context environment.
Closures in Swift have a lot of optimizations in place:
(1) Determine the number of parameters 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, can omit return)
(3) to be able to use simplified reference names, such as $ A, $ (starting from 0, representing the first I ...)
(4) The following closure syntax is provided (Trailing closure syntax)
Ii. Examples of use (examples listed here are summarized in the book "The Swift Programming Language")
Use the Sort method in the swift standard library to simplify closures in a step-by-step manner
A sort function requires two parameters
Number of parameters: array
Number two: A closure: With two parameters, the two parameter types are the same as the element types in the array, and 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//Descending sort
}
Call:
Sort (&names, backwards)
The use of such a method is equivalent to the callback backward approach.
another way: using closures
The complete closure is written in curly braces with a list of parameters and a return value. Using Keywordin to show the beginning of the closure body
(1) (firststring:string, secondstring:string) closure list
(2)-bool Specifies that the closure return value type is bool
(3) The Inkeyword indicates the beginning of the closure body
Sort (&names, {(firststring:string, secondstring:string), Bool in return firststring > Secondstring
This allows for further simplification of the notation. Because the closure code is shorter, it can be written on a line
Sort (&names, {(firststring:string, secondstring:string), Bool in return firststring > secondstring})
The following further simplifies the way of writing: according to the environment context itself to determine the type, the list does not indicate the type, and does not indicate the return value type, this is because Swift can guess according to the context, The type of firststring and secondstring will be the type of the names array element, and the return value type will be based on the return statement result
further simplification: implicit return (single-line statement closure), because the closure has only one line of code, can omit the return
Sort (&names, {firststring, secondstring in Firststring > secondstring})
further simplification: using simplified parameter names ($i, i=0,1,2 ... starting with 0), Swift will determine that the closure requires two parameters, and the type is the same as the names array element
Sort (&names, {$ > $})
the simplest way to do this: using Operators
Sort (&names, >)
iii. following closures (Trailing Closures)
Assume that the function requires a closure reference as a parameter, and that this is the last parameter, and that the closure expression is very long. It is very practical to use following closures.
The following closures can be placed outside the list of function references, which is outside the brackets. is to extract the closure from the list of functions to the back of the function to write, which is conducive to reading and use.
1. Or use the Sort method for example, the normal closure notation is as follows:
Sort (&names, {(firststring:string, secondstring:string), Bool in return firststring > Secondstring
However, it is possible to find that the second parameter in the sort function is long and not conducive to reading, and we are able to use the following closures to transform. The code is as follows:
Sort (&names) { (firststring, secondstring), Bool in return firststring > secondstring}
2. The map method uses an example to output an array of corresponding strings
var numbers = [1,2,3]let strings = Numbers.map ({ var number), String in var output = "" And while number ; 0 { output = String (number%) + output number /= } return output})
Note that map is a method, and its parameters have only one closure. So we can use the same form of following closures. Written such as the following form
var numbers = [1,2,3]let strings = Numbers.map () { (var number), String in var output = "" And while number > 0 { output = String (number%) + output number /= } return output}
The map function does not have any other parameters. There is only one closure parameter. So the "()" behind the map can be omitted, and finally the following closures can be written in the form of
var numbers = [1,2,3]let strings = numbers.map{ (var number), String in var output = "" And while number > 0 { output = String (number%) + output number /= } return output}
Iv. Capturing Values
Closures can be captured to defined constants and variables based on the environment context.
Closures are able to reference and alter these captured constants and variables. The simplest form of closure in Swift is a nested function.
Func increment (#amount: int)--((), int) { var total = 0 func incrementamount (), int () = Total + = Amount//Total is a variable in the body of an external function. Here is the ability to capture return total } return incrementamount//return a nested function (closure) }
closures are reference types , so incrementbyten declarations as constants can also change the total
Let Incrementbyten = Increment (amount:10) Incrementbyten ()//Return 10,incrementbyten is a closed package // Here is no change to the increment reference, so the previous value will be saved Incrementbyten ()//Return Incrementbyten ()//Return Incrementbyone = Increment (amount:1) incrementbyone ()//return 1 incrementbyone ()//return 2 Incrementbyten ()//Return Incrementbyone ()//Return 3
The circular reference problem of closed package
During the objective-c period, the block's circular reference problem had to be considered when using block. The measures taken at that time were to weaken the side of the circular reference. For example:
__weak typeof (self) wself = self;
Mode one: Use unowned keyword
The same problem also exists in closures in Swift. In fact the general idea is consistent, we can use unowned keyword.
Example. Converts the properties of an object into an XML display:
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 Le T 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 code above. Self has a strong reference to Ashtml's closure property, and Ashtml has a strong reference to self, so we can use [unowned self] to "weaken" self. The circular reference is thus lifted.
Note: unowned keyword is equivalent to __unsafe_unretained in OC when the object pointed to by the unsafe pointer is destroyed. The pointer still points to the memory address that was pointed to (wild pointer)
Mode two: Use weak keyword
Lazy var ashtml: () String = { [weak self] in if let text = self.text { return "<\ (Self.name) >\ (s Elf.text) </\ (self.name) > " } else { return" <\ (self.name) > " } }
Note:Weakkeyword is equivalent to __weak in OC when the object pointed to by the weak pointer is destroyed. The pointer points to nil on its own initiative
Method Three: The corresponding weakkeyword in OC
weak var weakself = selflazy var ashtml: () String = { if let Text = weakself.text { return ' <\ (weakself. Name) >\ (weakself.text) </\ (weakself.name) > " } else { return" <\ (weakself.name) > " } }
Note: One of the other and third methods used is more common.
vi. Examples of closures used in uikit real-world environments
The UI interface is as follows:
very easy to function
1. The above Gray view is your own definition of view (testview.swift). It includes a text input box and a "GO" button.
2. This next piece is the controller's view (Viewcontroller.swift), which includes a testlabel.
3. After clicking "GO" button, the contents of the text box will be recalled to the label display in Viewcontroller.swift.
Testview.swift Code:
Class Testview:uiview {private weak var textfield1:uitextfield! var testclosure: ((str1:string)-Void)? Override Init (Frame:cgrect) {super.init (frame:frame) var size = Uiscreen.mainscreen (). bounds.size Self.frame = CGRectMake (0, 0, size.width, kviewheight) Self.backgroundcolor = Uicolor.graycolor () var textField1 = Uitextfield (Frame:cgrectmake (Ten, ()) Textfield1.backgroundcolor = Uicolor.whiteco Lor () Self.addsubview (textField1) self.textfield1 = textField1 var btn = UIButton (frame:cgre Ctmake (+, ()) Btn.settitle ("GO", ForState:UIControlState.Normal) Btn.addtarget (Self, Action: "Sh Owresult ", ForControlEvents:UIControlEvents.TouchDown) Self.addsubview (BTN)} func Showresult () { Self.testclosure?(Str1:self.textField1.text)} Required Init (coder Adecoder:nscoder) {fatalerror ("init (coder:) have not been implemented")}}
the code. I have defined a testclosure closure property that calls its method when the "GO" button is clicked. Notice the definition of closures
var testclosure: ((str1:string)-Void)?
It is nullable because the work of assigning values to the Testclosure closure property is not necessarily complete in the controller viewcontroller.swift.
So when you call a closure, you write
Self.testclosure? (Str1:self.textField1.text)
The code for the Viewcontroller.swift assignment, for example, is as follows:
Class Viewcontroller:uiviewcontroller { @IBOutlet weak var testlabel:uilabel! Override Func Viewdidload () { super.viewdidload () var tab = TestView () tab.testclosure = { [unowned Self]//Remove circular reference (str1:string), Void in self.testLabel.text = "First record:\ (STR1)" } Self.view.addSubview (tab) } override Func didreceivememorywarning () { Super.didreceivememorywarning () //Dispose of any resources, can be recreated. }}
Swift: Closure (Closures)