Swift超基礎語法(閉包篇)

"閉包,Swift中的新概念,然而除了寫法不同,實際上用法與用途都和OC中的Block沒什么不同"

閉包

Swift中并沒有block的概念,但為了取代block,Swift中提出了另一個概念"閉包"(我猜它的英文名應該叫B-Box吧...童言無忌~)

Tips:
閉包經常用于回調,本質也是一個代碼塊

閉包的使用方法:

  • 閉包的寫法:
    • 對比OC中的block,我們知道閉包的完整用法有三步:
1.閉包的定義:
    var 閉包名:(形參列表)->(返回值)
2.閉包的實現(xiàn):
    閉包名 = {
        (形參) -> 返回值類型 in
        // 執(zhí)行代碼
    }
3.閉包的回調:
    閉包名(形參)
  • 我們在這里模擬一個場景:創(chuàng)建一個網絡請求工具類,在子線程中請求數(shù)據(jù),在主線程中刷新UI,以此為例子來看一下閉包的使用方法
例:模擬網絡請求工具類
//創(chuàng)建網絡請求工具類
class HttpTool {
    func loadData(completeHandle : () -> ()) {  //1.第一步:定義發(fā)送網絡請求的方法,傳入一個"請求完成后回調的閉包"(這一步相當于定義了一個() -> ()類型的閉包)
        dispatch_async(dispatch_get_global_queue(0, 0)) {   //跳轉到子線程
            print("請求數(shù)據(jù) -> \(NSThread.currentThread())")  //模擬發(fā)送網絡請求,同時打印當前所在線程
            dispatch_sync(dispatch_get_main_queue(), {  //跳轉到主線程
                completeHandle()  //3.第三步:在主線程執(zhí)行回調
            })
        }
    }
}
//外部調用
        let tool = HttpTool()
        tool.loadData({() -> (Void) in  //2.第二步:實現(xiàn)閉包中的方法
            print("刷新UI -> \(NSThread.currentThread())")
        })
//打印結果
請求數(shù)據(jù) -> <NSThread: 0x7fe162c26a40>{number = 2, name = (null)}
刷新UI -> <NSThread: 0x7fe162d01730>{number = 1, name = main}
  • 閉包實現(xiàn)的簡便寫法
    如果閉包沒有返回值沒有參數(shù),那么可以省略掉:"() -> () in",那么上面例子中的"外部調用"部分可以簡寫為如下:
        let tool = HttpTool()
        tool.loadData({  //省略掉了() -> (Void) in
            print("刷新UI -> \(NSThread.currentThread())")
        })
  • 閉包的超簡便寫法(尾隨閉包):
    尾行尾隨閉包顧名思義,當我們的閉包是整個函數(shù)中的最后一個參數(shù)的時候可以把整個閉包(整個大括{}號中的部分)拿出來放到()后面,那我們繼續(xù)簡化例子中"外部調用"的部分
        tool.loadData(){  //注意:此時閉包作為函數(shù)的最后一個參數(shù),被拿到了參數(shù)列表外部,并且緊跟在()后面
            print("刷新UI -> \(NSThread.currentThread())")
        }

尾隨閉包的進一步簡化:當函數(shù)中只有一個參數(shù)的時候,并且恰好這個參數(shù)是閉包的時候,小括號()可以不寫!在追求極簡的Swift語言中,這種最簡化的閉包寫法,無疑是apple大力推薦的,如下:

        let tool = HttpTool()
        tool.loadData{  //注意:函數(shù)的參數(shù)列表()也可以不寫了哦
            print("刷新UI -> \(NSThread.currentThread())")
        }

Swift中快速解決閉包引發(fā)的循環(huán)引用:

  • block引發(fā)的循環(huán)引用
    block會對內部的對象進行強引用,我們拿當前控制器的self來舉例:
    • 當前控制器中定義一個httpTool類型的屬性tool,并將其實例化,則控制器強引用了tool
self.tool = HttpTool()  //self強引用tool
  • 如果tool中定義閉包屬性,則tool強引用該閉包
class HttpTool {
    var completeHandle : (() -> ())?
    func changeViewColor() -> Void {
        completeHandle!()
    }
}
  • 如果閉包內部調用了self的某一些方法,則閉包強引用了self,
        self.tool!.completeHandle = {
            self.view.backgroundColor = UIColor.redColor()
        }

以上造成了循環(huán)引用

  • 解決循環(huán)引用的辦法:
    • weakSelf
      在OC中,我們常常定義一個變量來弱引用self,以此來代替self在閉包中使用
        self.tool = HttpTool()
        weak var wSelf = self //這里的wSelf是一個可選類型,因為self被釋放后為nil,所以wSelf有可能指向nil
        self.tool!.completeHandle = {
            wSelf!.view.backgroundColor = UIColor.redColor()
        }
        self.tool?.changeViewColor()
  • [weak self]
    Swift中特有的方法,這種寫法會讓閉包內所有的self都變?yōu)槿跻?/li>
        self.tool = HttpTool()
        self.tool!.completeHandle = {[weak self]() -> () in
            self!.view.backgroundColor = UIColor.redColor()  //這里的self為可選類型,有可能指向空(當其引用的控制器被釋放時,改變指向為nil)
        }
        self.tool?.changeViewColor()
  • [unowned self]
    Swift中特有的方法,這種寫法會讓閉包內所有的self都變?yōu)槿跻?與[weak self]不同的是,unowned引用的self所指向的實例被銷毀后,仍然會指向原有的存儲空間,所以這時閉包里的self既不是optional類型,也不可以指向nil
        self.tool = HttpTool()
        self.tool!.completeHandle = {[unowned self]() -> () in
            self.view.backgroundColor = UIColor.redColor()  //這里的self不是可選類型,故不需要強制解包
        }
        self.tool?.changeViewColor()
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容