Swift-閉包

Swift-閉包

Swift閉包的含義

  • 閉包是自包含的功能代碼塊,可以用作函數的參數或者返回值

  • 閉包可以捕獲上下文中的任何常量以及變量的引用-變量和常量的自封閉

  • 閉包是引用類型

Swift中閉包的表現形式

  • 全局函數:全局函數都是閉包,這些閉包都有命名,但是不能捕獲任何值

  • 嵌套函數:嵌套函數也都是閉包,這些閉包有名字,并且能夠捕獲當前上下文中的常量和變量的值

  • 閉包表達式:閉包表達式都是無名閉包,可以捕獲上下文中的值

簡單了解一下閉包

  • 最簡單的閉包:

    {}

    閉包的執行:

    {}()

    OK,玩一下最接地氣的playground

    定義閉包:

img_01.png
閉包執行:
img_02.png
  • 項目中經常使用到的閉包
    1. 懶加載

       private lazy var tmpStr:UILabel = {
           let tmpLabel:UILabel = UILabel()
           return tmpLabel
           }()
      
    2. 定義網絡回調(類似OC網絡回調的Block)

       typealias NETERRORCLOCURE = (ErrorProtocol) -> Void
       typealias NETSUCCESSCLOSURE = (AnyObject) -> Void
      
       import UIKit
      
       class ZHNetWorkApi: NSObject {
                   static func login(phoneNum:String, password:String, netError error:NETERRORCLOCURE? = nil,  success successData:NETSUCCESSCLOSURE? = nil){
        }
       }
      

      調用接口:

       ZHNetWorkApi.login(phoneNum: "zhu", password: "hou", netError: {[weak self] (error) in
       
               guard let instance = self else {
                   return
            }
               instance.tmpStr.text = "lin"
           }) {[weak self] (data) in
           }
      

官方文檔中的閉包

  • 閉包-Closures

  • Sorted方法-The Sorted Method

  • 閉包表達式-Closure Expression Syntax

  • 類型推斷-Inferring Type From Context

  • 省略return的單行表達式閉包-Implicit Returns from Single-Expression Closures
    - 官方描述:

        “Single-expression closures can implicitly return the result of their single expression by omitting the return keyword from their declaration”
        單一表達式閉包在返回結果的時候可以省略return關鍵字
    
    -   例子:
        我們首先聲明一個方法,該方法兩個參數,一個NSinteger類型的數據,一個閉包,該閉包有參數有返回值:
    
        func closureTest_A(a:NSInteger,closure:((NSInteger, NSInteger) -> NSInteger)) {
                  closure(a, a - 10)
        }
        
        我們來調用一下這個函數:
            -   調用方式一:
                closureTest_A(a: 10) { (aa, bb) -> NSInteger in
                        return aa + bb
                }
                注意:這是一個尾隨閉包(下面有介紹),所以閉包可以寫在()之外
                
            -   調用方式二:
                closureTest_A(a: 10) { (aa, bb) -> NSInteger in
                        aa + bb
                }
            
            -   調用方式三:
                我可能需要在閉包中做更多的計算操作,然后才返回數據
                closureTest_A(a: 10) { (aa, bb) -> NSInteger in
                        let cc = aa - bb
                        return aa + bb
                }
                
                OK,那么問題來了,怎么是不正確的調用呢?很簡單,將上面的return省略掉,這時候就會報錯“missing return ...”。也就是說,當閉包中含有多個表達式的時候,是不可省略return關鍵字的(除非閉包沒有返回值)。原因是這種情況下,swift無法確定那個表達式才是真正應該返回的數據
                那么有的同學就會想了,一個返回Bool類型的閉包中,去執行兩個表達式語句,一個是bool類型,一個是NSinteger類型,這種情況下省略return可以自動返回Bool類型的運算結果嗎?答案是不會的,還是同樣的報錯“missing return”,下面是錯誤的例子
          closureTest_A(a: 10) { (aa, bb) -> NSInteger in
                         let cc = aa > bb
                        aa + bb
                }
    -   總結:
        閉包省略renturn的充要條件:
            -   閉包有返回值
            -   閉包有且只有一條執行語句
            -   該條執行語句的結果類型和閉包的返回值類型必須一致
    
  • 參數名簡寫-Shorthand Argument Names
    - 官方描述:

        “Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.”
        意思很簡單,就是說,訪問內聯閉包的參數的時候可以用‘$’+下標(第幾個參數)的形式。$0就是訪問第一個參數,$1就是訪問第二個參數。。。
        
    -   官方例子:
    
        let reversedNames = names.sorted(isOrderedBefore: {
            $0 > $1
        })
        
        再看一下這個函數的聲明
        public func sorted(isOrderedBefore: @noescape (Element, Element) -> Bool) -> [Element]
        
        上面的函數的參數是一個非逃逸閉包,這個非逃逸閉包有兩個參數,對這兩個參數的訪問,可以使用'$' + 下標的方式
        
        而一般我們比較習慣的寫法是下面這樣的:
        let bbb = names.sorted {[unowned self] (a, b) -> Bool in
                return a > b
        }
    
        OK,我們來看看這個方法是怎么一步步演化的
        首先是最繁瑣的調用-參數名+參數類型(閉包-參數+返回值)
        let reversedNames = names.sorted(isOrderedBefore: { (a,b) -> Bool in
                return a > b
        })
        
        OK我們再簡單一點點,怎么簡單呢?哈哈,他是一個尾隨閉包,再次簡化
        let reversedNames = names.sorted { (a, b) -> Bool in
                return a > b
        }   
        
        再來,通過下標訪問簡化操作
        let bbb = names.sorted {
                return $0 > $1
        }
        
        再來,把return也干掉           
        let bbb = names.sorted {
                $0 > $1
        }
        
    -   注意事項,如果閉包的的參數是明確的,也就是 ‘in’和之前的代碼沒有省略的情況下,是不可以使用'$' + 下標的方式訪問閉包參數的,否則會報如下錯誤“ Anonymous closure arguments cannot be used inside a closure that has explicit arguments”
    
    - 讓我們來看一個有趣的現象:數組的排序
        我們在上面使用過了一個方法 names.sorted,如果你自己試驗的時候回發現一個很有其的現象
    
  • 運算符函數-Operator Functions
    - 官方描述:
    “Classes and structures can provide their own implementations of existing operators. This is known as overloading the existing operators.”
    也就是說,類和結構體是能夠針對已存在的運算符(‘+’,’-‘,’*‘,’、‘)實現自己的對于這些運算符的操作。這種方式叫做重載運算符。
    實際上,運算符不單單可以被重載,如果有需要的話,你也可以定義自己的運算符,比如'+++','---','==='。

    -   官方例子:
        reversedNames = names.sorted(isOrderedBefore: >)
        上面的例子,是官方文檔中給出的例子,可以看到參數是一個'>',按住Commond點擊去之后可以查看'>'的定義:
        public func ><T : Comparable>(lhs: T, rhs: T) -> Bool
        很明顯這是一個閉包,有兩個參數和一個返回值
    
  • 尾隨閉包-Trailing Closures
    - 官方對尾隨閉包的描述
    “A trailing closure is written after the function call’s parentheses, even though it is still an argument to the function”
    簡單來說尾隨閉包就是當一個函數或者方法有一個閉包作為參數回調,那么閉包可以寫在"()"的后面,而不是寫在"()"之間
    - 舉例子描述-01

        func funcA(str:NSString, closure:() -> Void) {
             _ = 1
        }
        
        上面定義了一個帶有閉包參數的函數,我們看一些對這個函數的調用方式:
            -   非尾隨閉包方式調用
                funcA(str: "zhuhoulin", closure: {
    
                })
                閉包包含在"()"之內
    
            -   尾隨閉包的方式調用
                funcA(str: "zhuhoulin") { 
    
                }
                閉包不包含在"()"之內
                
    -   舉例子描述-02
    
        func funcB(str:NSString, closure_A:() -> Void, closure_B:() -> Void) {
    
        }
        
        上面的例子中有兩個閉包參數,同樣也會有兩種調用方式
        -   非尾隨閉包
            funcB(str: "zhuhoulin", closure_A: { 
    
                    }, closure_B: {
    
            })
        
        -   尾隨閉包
            funcB(str: "zhuhoulin", closure_A: { 
    
               }) { 
    
            }
        對比上面兩種方式,只有最后一個閉包才有成為尾隨閉包的這個權利
        
    -   總結-什么是尾隨閉包
        -   閉包作為函數的參數,并且這個參數是最后一個參數
        -   這個閉包包含的代碼塊不可不用寫在"()"之內,而是寫在的"()"之后的"{}"之內
    
  • 值捕獲-Capturing Values

  • 閉包是引用類型-Closures Are Reference Types

  • 非逃逸閉包-Nonescaping 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.”
        其實意思很簡單,如果一個函數或者方法中,有一個閉包式的參數,如果這個閉包式的參數在return之前已經被執行,那么這個閉包就是非逃逸閉包
    
    -   官方例子:
        func someFunctionWithNonescapingClosure(closure: @noescape () -> Void) {
                closure()
        }
        很簡單,閉包在函數中執行了就是非逃逸閉包,沒有執行就是逃逸閉包
        
    -   個人使用的一個栗子:
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容

  • 閉包(Closures)是自包含的功能代碼塊,可以在代碼中使用或者用來作為參數傳值。 Swift 中的閉包與 C ...
    零度_不結冰閱讀 411評論 2 1
  • 閉包可以從定義它們的上下文中捕獲和存儲對任何常量和變量的引用。 這被稱為關閉這些常量和變量。 Swift處理所有的...
    Joker_King閱讀 597評論 0 2
  • 閉包是自包含的函數代碼塊,可以在代碼中被傳遞和使用。Swift 中的閉包與 C 和 Objective-C 中的代...
    窮人家的孩紙閱讀 1,729評論 1 5
  • * 閉包 是自包含的函數代碼塊,可以在代碼中被傳遞和使用。swift中的閉包和Objective-C中的代碼塊(b...
    EndEvent閱讀 865評論 4 8
  • 雖然我的臉很大 但沒有造成任何影響。 ——泥鰍胡子
    唏噓同學閱讀 1,701評論 0 2