- 閉包和OC中的Block差不多版扩,也是保存一段代碼翎朱,在適當(dāng)?shù)臅r(shí)候執(zhí)行,一般用于一些耗時(shí)操作露戒,也可以傳遞值
- 區(qū)別:block類(lèi)似于匿名函數(shù)描验,而閉包就是用來(lái)定義函數(shù)的白嘁,Swift中的函數(shù)其實(shí)就是閉包
- 注意:Swift中,要求一個(gè)類(lèi)的屬性必須有初始值挠乳,如果沒(méi)有权薯,可以寫(xiě)個(gè)問(wèn)號(hào)表示是可選類(lèi)型。也就是說(shuō)睡扬,如果類(lèi)的屬性不是可選類(lèi)型,那么必須有初始化值
- 所以黍析,在viewController中定義一個(gè)閉包卖怜,也必須有個(gè)初始值,或者加個(gè)問(wèn)號(hào)阐枣。
- 注意問(wèn)號(hào)的位置马靠,如果直接放在了后面一個(gè)括號(hào)后面,表示返回值是可選類(lèi)型蔼两,而我們現(xiàn)在要表示閉包是可選類(lèi)型甩鳄。所以要把閉包整體括起來(lái),把問(wèn)號(hào)放在后面
// 定義一個(gè)閉包屬性(類(lèi)似OC的strong屬性)
// 返回值為空额划,那么可以用()代替
var finished: (() -> ())?
- 定義完屬性妙啃,在viewDidLoad中給他初始化
- 格式:
//類(lèi)型的格式:(形參列表) -> 返回值類(lèi)型
//值的格式:
{
(形參列表) -> 返回值類(lèi)型
in // in的作用是分隔需要執(zhí)行的代碼
需要執(zhí)行的代碼
}
- 示例:沒(méi)有形參,沒(méi)有返回值的閉包
self.finished = {
() -> ()
in
print("我被調(diào)用了")
}
// 調(diào)用,此處加嘆號(hào)是因?yàn)楸仨毐WC閉包中有值才能調(diào)用(類(lèi)似OC中block也必須先判斷block是否有值)
self.finished!()
- 注意點(diǎn)
- Swift中self用的比較少俊戳,一般僅用于閉包中揖赴,所以看到self就要想起閉包
具體使用
- 經(jīng)典子線程耗時(shí)操作,主線程更新UI
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("執(zhí)行了耗時(shí)操作")
print(NSThread.currentThread())
dispatch_async(dispatch_get_main_queue(), { () -> Void in
print("更新了UI")
print(NSThread.currentThread())
})
}
- 用閉包封裝一個(gè)創(chuàng)建scrollView的方法抑胎,并且在scrollView里創(chuàng)建子控件燥滑。創(chuàng)建的子控件類(lèi)型和個(gè)數(shù)由調(diào)用者決定
- 這個(gè)示例中,閉包的返回值由調(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("標(biāo)題\(index)", forState: UIControlState.Normal)
btn.frame = CGRect(x: index * width, y: 0, width: width, height: 44)
return btn
}
view.addSubview(sc)
閉包的簡(jiǎn)寫(xiě)
- 來(lái)個(gè)帶閉包的函數(shù)赃蛛,并且調(diào)用
func loadData(finished: ()->())
{
print("執(zhí)行了耗時(shí)操作")
// 調(diào)用閉包
finished()
}
loadData ({ () -> () in
print("耗時(shí)操作執(zhí)行完畢")
})
- 如果閉包沒(méi)有參數(shù),那么in和in之前的閉包格式符號(hào)可以省略
- 如果閉包是函數(shù)形參列表的最后一個(gè)形參搀菩,那么可以把閉包寫(xiě)到圓括號(hào)后面
- 如果形參列表只有閉包一個(gè)參數(shù)焊虏,那么圓括號(hào)可以省略(系統(tǒng)就是這么做的)
- 于是調(diào)用上面那個(gè)函數(shù)就變成了這樣
loadData {
print("耗時(shí)操作執(zhí)行完畢")
}
閉包的循環(huán)引用
- 在閉包中使用外接對(duì)象,為了在調(diào)用閉包的時(shí)候保證這個(gè)對(duì)象沒(méi)有被釋放秕磷,必須對(duì)這個(gè)外界對(duì)象加一個(gè)self.意思是對(duì)其進(jìn)行強(qiáng)引用
- 如果把一個(gè)閉包保存為控制器的屬性诵闭,在這個(gè)閉包中又調(diào)用了控制器的view,用到了self(控制器)澎嚣,那么就會(huì)導(dǎo)致強(qiáng)引用循環(huán)
- 類(lèi)似于OC疏尿,設(shè)置一個(gè)weakSelf即可解決這個(gè)問(wèn)題
- 注意在閉包中使用weakSelf的時(shí)候要加問(wèn)號(hào)。因?yàn)槭莣eak的表示弱引用易桃,隨時(shí)可能釋放褥琐,可能是nil;而只要有可能是nil的對(duì)象必須是可選類(lèi)型晤郑〉谐剩可以直接強(qiáng)制解包告訴它一定有值,問(wèn)號(hào)改成感嘆號(hào)
weak var weakSelf = self
loadData ({ () -> () in
print("耗時(shí)操作執(zhí)行完畢")
weakSelf!.view.backgroundColor = UIColor.redColor
})
- 還有個(gè)寫(xiě)法:可以在閉包的形參列表圓括號(hào)前加上
[weak self]
,表示在此閉包中調(diào)用的self都是weak的
loadData ({ [weak self] () -> () in
print("耗時(shí)操作執(zhí)行完畢")
self!.view.backgroundColor = UIColor.redColor
})
- 解決方式二:用__unsafe_unretained
- OC中weak的特點(diǎn):如果對(duì)象被釋放造寝,會(huì)自動(dòng)賦值為nil
- OC中__unsafe_unretained的特點(diǎn):如果對(duì)象被釋放磕洪,不會(huì)賦值為nil,而是指向了一塊壞內(nèi)存诫龙∥鱿裕可以用這個(gè)來(lái)解決block的循環(huán)引用問(wèn)題
- Swift可以用
unowned
來(lái)達(dá)到相同的效果。注意不用加問(wèn)號(hào)或者嘆號(hào)了签赃,因?yàn)獒尫藕蟛粫?huì)是nil
loadData ({ [unowned self] () -> () in
print("耗時(shí)操作執(zhí)行完畢")
self.view.backgroundColor = UIColor.redColor
})
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者