swift-基礎-閉包

  • 閉包和OC中的Block差不多,也是保存一段代碼,在適當?shù)臅r候執(zhí)行,一般用于一些耗時操作,也可以傳遞值
  • 區(qū)別:block類似于匿名函數(shù),而閉包就是用來定義函數(shù)的,Swift中的函數(shù)其實就是閉包
  • 注意:Swift中,要求一個類的屬性必須有初始值,如果沒有,可以寫個問號表示是可選類型。也就是說,如果類的屬性不是可選類型,那么必須有初始化值
  • 所以,在viewController中定義一個閉包,也必須有個初始值,或者加個問號。
    • 注意問號的位置,如果直接放在了后面一個括號后面,表示返回值是可選類型,而我們現(xiàn)在要表示閉包是可選類型。所以要把閉包整體括起來,把問號放在后面
// 定義一個閉包屬性(類似OC的strong屬性)
// 返回值為空,那么可以用()代替
var finished: (() -> ())?
  • 定義完屬性,在viewDidLoad中給他初始化
  • 格式:
//類型的格式:(形參列表) -> 返回值類型
//值的格式:
{
    (形參列表) -> 返回值類型
    in // in的作用是分隔需要執(zhí)行的代碼
    需要執(zhí)行的代碼
}
  • 示例:沒有形參,沒有返回值的閉包
self.finished = {
    () -> ()
    in
    print("我被調(diào)用了")
}
// 調(diào)用,此處加嘆號是因為必須保證閉包中有值才能調(diào)用(類似OC中block也必須先判斷block是否有值)
self.finished!()
  • 注意點
    • Swift中self用的比較少,一般僅用于閉包中,所以看到self就要想起閉包

具體使用

  • 經(jīng)典子線程耗時操作,主線程更新UI
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in

    print("執(zhí)行了耗時操作")

    print(NSThread.currentThread())

    

    dispatch_async(dispatch_get_main_queue(), { () -> Void in

        print("更新了UI")

        print(NSThread.currentThread())

    })

}
  • 用閉包封裝一個創(chuàng)建scrollView的方法,并且在scrollView里創(chuàng)建子控件。創(chuàng)建的子控件類型和個數(shù)由調(diào)用者決定
    • 這個示例中,閉包的返回值由調(diào)用者傳給方法,而閉包中的參數(shù)是由方法傳給調(diào)用者
func creatScrollView(btnCount: ()-> Int, btnWithIndex: (index:Int) ->UIView) -> UIScrollView

    {

        let sc = UIScrollView(frame: CGRect(x: 0, y: 100, width: 375, height: 44))

        sc.backgroundColor = UIColor.redColor()

        let count = btnCount()

        for i in 0..<count

        { // subView由調(diào)用者決定,而index由這里決定并傳給調(diào)用者

            let subView = btnWithIndex(index: i)

            sc.addSubview(subView)

            sc.contentSize = CGSize(width: CGFloat(count) * subView.bounds.width, height: 44)

        }

        

        return sc

    }
// 調(diào)用
let sc = creatScrollView({ () -> Int in

            return 15

            }) { (index) -> UIView in

                let width = 80

                let btn = UIButton()

                btn.backgroundColor = UIColor.greenColor()

                btn.setTitle("標題\(index)", forState: UIControlState.Normal)

                btn.frame = CGRect(x: index * width, y: 0, width: width, height: 44)

                return btn

        }

        view.addSubview(sc)

閉包的簡寫

  • 來個帶閉包的函數(shù),并且調(diào)用
func loadData(finished: ()->())

{

    print("執(zhí)行了耗時操作")

    // 調(diào)用閉包

    finished()

}

loadData ({ () -> () in

    print("耗時操作執(zhí)行完畢")

})
  • 如果閉包沒有參數(shù),那么in和in之前的閉包格式符號可以省略
  • 如果閉包是函數(shù)形參列表的最后一個形參,那么可以把閉包寫到圓括號后面
  • 如果形參列表只有閉包一個參數(shù),那么圓括號可以省略(系統(tǒng)就是這么做的)
  • 于是調(diào)用上面那個函數(shù)就變成了這樣
loadData {
    print("耗時操作執(zhí)行完畢")
}

閉包的循環(huán)引用

  • 在閉包中使用外接對象,為了在調(diào)用閉包的時候保證這個對象沒有被釋放,必須對這個外界對象加一個self.意思是對其進行強引用
  • 如果把一個閉包保存為控制器的屬性,在這個閉包中又調(diào)用了控制器的view,用到了self(控制器),那么就會導致強引用循環(huán)
  • 類似于OC,設置一個weakSelf即可解決這個問題
    • 注意在閉包中使用weakSelf的時候要加問號。因為是weak的表示弱引用,隨時可能釋放,可能是nil;而只要有可能是nil的對象必須是可選類型??梢灾苯訌娭平獍嬖V它一定有值,問號改成感嘆號
weak var weakSelf = self
loadData ({ () -> () in

    print("耗時操作執(zhí)行完畢")
    weakSelf!.view.backgroundColor = UIColor.redColor

})
  • 還有個寫法:可以在閉包的形參列表圓括號前加上[weak self],表示在此閉包中調(diào)用的self都是weak的
loadData ({ [weak self] () -> () in

    print("耗時操作執(zhí)行完畢")
    self!.view.backgroundColor = UIColor.redColor

})
  • 解決方式二:用__unsafe_unretained
    • OC中weak的特點:如果對象被釋放,會自動賦值為nil
    • OC中__unsafe_unretained的特點:如果對象被釋放,不會賦值為nil,而是指向了一塊壞內(nèi)存??梢杂眠@個來解決block的循環(huán)引用問題
    • Swift可以用unowned來達到相同的效果。注意不用加問號或者嘆號了,因為釋放后不會是nil
loadData ({ [unowned self] () -> () in

    print("耗時操作執(zhí)行完畢")
    self.view.backgroundColor = UIColor.redColor

})
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容