1. 程式人生 > >Swift學習記錄 -- 14.閉包的使用和解決迴圈引用方法

Swift學習記錄 -- 14.閉包的使用和解決迴圈引用方法

Swift中的閉包 , 幾乎和OC中的block一模一樣 , 我個人又比較偏好block , 所以覺得閉包還是蠻不錯的 . 在迴圈引用問題上 , 解決方案也更加簡潔

// HttpTool類
import UIKit

class HttpTool: NSObject {

    //閉包寫法 : (引數列表) -> (返回值型別)
    func loadData(callBack:(jsonData:String) -> ()) {

        //模擬網路請求 (因為我這裡使用的是xCode低版本 , 所以方法名稱具體有所不一樣,但是寫法都是差不多的)
        dispatch_async(dispatch_get_global_queue(0
, 0)) { print("傳送網路請求 -- \(NSThread.currentThread())") //主執行緒更新UI dispatch_async(dispatch_get_main_queue(), { callBack(jsonData: "json資料") }) } } //模擬網路請求二 //定義閉包型別屬性,儲存閉包回撥操作 var backOperation:((jsonData:String) ->
())? = nil func loadMoreData(backOperation:(jsonData:String) ->() ) { //儲存操作 self.backOperation = backOperation //子執行緒請求 dispatch_async(dispatch_get_global_queue(0, 0)) { print("傳送網路請求:\(NSThread.currentThread())") //主執行緒回撥更新UI dispatch_async(dispatch_get_main_queue()) { // backOperation(jsonData: "json資料")
self.backOperation?(jsonData:"json資料") } } } }
//未涉及迴圈引用情況 : 
       //建立HttpTool例項物件
        let tool :HttpTool = HttpTool()

        //呼叫模擬網路請求方法
        tool.loadData { (jsonData) in

            print("獲取資料\(jsonData),進行主執行緒更新UI")
            print(NSThread.currentThread())
        }
        //注意:這種情況已經造成了迴圈引用 
        //閉包為self.tool屬性 , 故指標指向了閉包所在記憶體地址 . 在下述閉包中, 又訪問了self的記憶體地址進行背景色賦值 .

        //解決辦法迴圈引用方法一: (和OC一致 ,弱化self)
        weak var weakself = self
        tool.loadMoreData { (jsonData) in

            // weakself?的意思是:如果weakself沒有值 , 後面的程式碼將不會執行 , 如果weakself有值 , 那麼會自動將weakself進行解包,並執行後續程式碼
            // 個人覺得這點的設計還是非常人性化的,不知道這個語法前,我就在想,如果一直需要進行if判斷,然後解包, 這程式碼也太爛了
            weakself?.view.backgroundColor = UIColor.redColor()

            print("獲取資料\(jsonData) --- 當前執行緒:\(NSThread.currentThread())")
        }


        //解決迴圈引用方法二 :  (直接在大括號後,寫[weak self],推薦使用)
        tool.loadMoreData {[weak self] (jsonData) in

            //這裡的self依然變成可選型別
            self?.view.backgroundColor = UIColor.greenColor()
            print("獲取資料\(jsonData) --- 當前執行緒:\(NSThread.currentThread())")
        }


        //解決迴圈引用方法三: (不推薦 , 如果self為空, 直接崩潰)
     tool.loadMoreData {[unowned self] (jsonData) in

        self.view.backgroundColor = UIColor.greenColor()
        print("獲取資料\(jsonData) --- 當前執行緒:\(NSThread.currentThread())")
        }
     }


    //備註:
    /*  unowned 很類似於 OC中的__unsafe_unretained , 如果unowned修飾的弱引用,指標指向的物件銷燬 , 指標依然指向該記憶體地址 , 訪問殭屍物件,造成'野指標'錯誤

        weak 就相當於OC中的 __weak ,如果weak修飾的弱引用 ,指標指向的物件銷燬, 指標會立即置為nil
    */
    //控制器銷燬呼叫 , 相當於OC中的 dealloc
    deinit {

        print("---控制器銷燬")
    }

————– 補充 : 尾隨閉包

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //尾隨閉包:如果閉包作為函式的最後一個引數,那麼閉包可以將()省略

        //寫法1:
        test ({ (str) in
            print("\(str),world !")
        })

        //寫法2:
        test (){ (str) in
            print("\(str),world !")
        }

        //寫法3: (系統寫法)
        test { (str) in

            print("\(str),world !")
        }
    }
}
//測試函式
func test(bag:(str:String) ->()) {

    print("test ---")
    bag(str: "hello")
}