Swift的閉包(二):捕獲值

來源:互聯網
上載者:User

標籤:最簡   types   led   enter   參數傳遞   exp   first   ica   pes   

閉包可以從定義它的上下文中捕獲常量和變數。

在Swift中,捕獲值最簡單的例子是嵌套函數,舉個例子:

1 func makeIncrementer(forIncrement amount: Int) -> () -> Int {2     var runningTotal = 03     func incrementer() -> Int {4         runningTotal += amount5         return runningTotal6     }7     return incrementer8 }

在這個例子中incrementer()捕獲兩個值,分別是amount、runningTotal。可以運行一下,觀察結果:

1 let incrementByTen = makeIncrementer(forIncrement: 10)2 print(incrementByTen())     //103 print(incrementByTen())     //20
4 let incrementByNine = makeIncrementer(forIncrement: 9)5 print(incrementByNine()) //96 print(incrementByNine()) //18
7 print(incrementByTen()) //30

注意:如果你把閉包賦值給一個類執行個體的一個屬性,並且閉包通過指向(refer fo)執行個體或者執行個體的成員捕獲值,那麼,在閉包和這個執行個體間就會有一個強引用環。

閉包是參考型別(Reference Types)

閉包和函數都是參考型別。

Nonescaping Closures

當一個閉包作為參數傳遞給一個函數,但是在函數返回後調用的時候,我們說一個閉包是escaped的。當你聲明一個有一個閉包作為參數的函數的時候,你可以在參數類型前寫@nonescape來暗示這個closure不允許escape。如:

1 func someFunctionWithNonescapingClosure(closure: @noescape () -> Void) {2     closure()3 }

把一個閉包標記用@nonescape讓你在閉包內隱式的引用(refer to)self,看下這個例子:

 1 class SomeClass { 2     var x = 10 3     func doSomething() { 4         someFunctionWithNonescapingClosure { x = 200 } 5         someFunctionWithEscapingClosure { self.x = 100 } 6     } 7 } 8   9 let instance = SomeClass()10 instance.doSomething()11 print(instance.x)12 // Prints "200"13  14 completionHandlers.first?()15 print(instance.x)16 // 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.

Autoclosures可以延遲計算(delay evaluation),因為直到調用閉包時,閉包內的代碼才被運行。延遲計算對於有副作用或者計算代價昂貴的代碼非常有用,因為你可以控制什麼時候代碼進行evaluation。

 1 var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] 2 print(customersInLine.count) 3 // Prints "5" 4   5 let customerProvider = { customersInLine.remove(at: 0) } 6 print(customersInLine.count) 7 // Prints "5" 8   9 print("Now serving \(customerProvider())!")10 // Prints "Now serving Chris!"11 print(customersInLine.count)12 // Prints "4"

也可以傳遞給一個參數:

1 // customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]2 func serve(customer customerProvider: () -> String) {3     print("Now serving \(customerProvider())!")4 }5 serve(customer: { customersInLine.remove(at: 0) } )6 // Prints "Now serving Alex!"

使用@autoclosure:

1 // customersInLine is ["Ewa", "Barry", "Daniella"]2 func serve(customer customerProvider: @autoclosure () -> String) {3     print("Now serving \(customerProvider())!")4 }5 serve(customer: customersInLine.remove(at: 0))6 // Prints "Now serving Ewa!" 

注意:濫用autoclosure會使代碼晦澀難懂。

@autoclosure屬性隱含了@nonescape屬性,如果你想要一個autoclosure允許esacpe,可以這樣使用 @autoclosure(escaping) ,如:

 1 // customersInLine is ["Barry", "Daniella"] 2 var customerProviders: [() -> String] = [] 3 func collectCustomerProviders(_ customerProvider: @autoclosure(escaping) () -> String) { 4     customerProviders.append(customerProvider) 5 } 6 collectCustomerProviders(customersInLine.remove(at: 0)) 7 collectCustomerProviders(customersInLine.remove(at: 0)) 8   9 print("Collected \(customerProviders.count) closures.")10 // Prints "Collected 2 closures."11 for customerProvider in customerProviders {12     print("Now serving \(customerProvider())!")13 }14 // Prints "Now serving Barry!"15 // Prints "Now serving Daniella!"

 

Swift的閉包(二):捕獲值

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.