The concept of closure in Swift is similar to lambdas in .Net C# or blocks in C and Objective-C, but it is more powerful in Swift.
A closure in Swift can capture constants and variables in its context or its outer function. Closure provides a way to plug in dynamic codes. In advanced level, a closure can be used as a type passing to a function's parameter or return result.
Depending on how the closure is used in parameters, the closure can be escaped or none-escaped. This is an advanced feature. My understand of escaped closure is the one kept somewhere for later call, while none-escaped closure will be called in function.
In the following example, I modified codes in Mac Developer Library to explore the advanced feature. It was hard to comprehensive at first. However, I figured out how it works with some modifications.
It is amazed to see that closure, as in function parameters, can be either used and through away, or stored for later use. In most cases of completion handler, closure is called at later completion time. The following simple example explains how it works.
- /* The closure in parameter will be called in func
- the closure will be through away, not stored for later use */
- func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) {
- print("closure as @noescape parameter called and not saved")
- closure()
- }
- // array to store closures
- var completionHandlers: [() -> Void] = []
- /* The closure in parameter will NOt be called in func
- instead, stored into array for later call.
- */
- func someFunctionWithEscapingClosure(closure: () -> Void) {
- print ("add closure to complitionHandlers array")
- completionHandlers.append(closure)
- }
- // Example class with property x modified by closure
- // referenced by above funcs
- class SomeClass {
- var x = 10
- func doSomething() {
- someFunctionWithEscapingClosure {
- let value = 100
- print("set instance.x to \(value)")
- self.x = value }
- someFunctionWithNoescapeClosure {
- let value = 200
- print("set instance's x to \(value)")
- x = value }
- }
- }
- let instance = SomeClass()
- print("instance of SoSomething created, and method doSomething() called")
- instance.doSomething()
- print("instance.x: \(instance.x)")
- print("Call complitionHandler's first. Escaped closure being involked")
- completionHandlers.first?()
- print("instance.x: \(instance.x)")
The
func
at line 3 has a closure as none-escaped parameter, and the closure is called at line 5, not kept. While the func
at line 9 has a closure as escaped closure, appended to outer array at line 15.As a result, after an instance of
SomeClass
is created at line 34, and its method of doSomething()
is called, the instance property value x
is set 200 by func
call of someFunctionWithNoescapeSclosure
at line 27.The instance's property
x
is set to 100 as the result of calling global array's first item, which triggers escaped closure called.And the result is as follows:
instance of SoSomething created, and method doSomething() called add closure to complitionHandlers array closure as @noescape parameter called and not saved set instance's x to 200 instance.x: 200 Call complitionHandler's first. Escaped closure being involked set instance.x to 100 instance.x: 100
References
- Mac Developer Library: Swift Programming Language 2.1
0 comments:
Post a Comment