Swift3:@escaping

@escaping

在Swift3中,閉包默認(rèn)是非逃逸的。在Swift3之前,事情是完全相反的:那時(shí)候逃逸閉包是默認(rèn)的,對于非逃逸閉包,你需要標(biāo)記@noescaping。Swift3的行為更好。因?yàn)樗J(rèn)是安全的:如果一個(gè)函數(shù)參數(shù)可能導(dǎo)致引用循環(huán),那么它需要被顯示地標(biāo)記出來。@escaping標(biāo)記可以作為一個(gè)警告,來提醒使用這個(gè)函數(shù)的開發(fā)者注意引用關(guān)系。非逃逸閉包可用被編譯器高度優(yōu)化,快速的執(zhí)行路徑將被作為基準(zhǔn)而使用,除非你在有需要的時(shí)候顯式地使用其他方法。

@escaping標(biāo)明這個(gè)閉包是會(huì)“逃逸”,通俗點(diǎn)說就是這個(gè)閉包在函數(shù)執(zhí)行完成之后才被調(diào)用。為了體現(xiàn)@escaping的作用,我們在之前先做一個(gè)鋪墊:

func doWork(block:()->()) {

print("header")

block()

print("footer")

}

doWork {

print("work")

}

//控制臺(tái)打印的消息如下:

//header

//work

//footer

對于上述的block調(diào)用是同步行為。我們修改一下代碼,將block放到一個(gè)異步操作中,讓它在doWork返回后被調(diào)用。這個(gè)時(shí)候我們就需要用@escaping標(biāo)記表明這個(gè)閉包是會(huì)“逃逸”的。

func doWorkAsync(block: @escaping () -> ()) {

DispatchQueue.main.async {

block()

}

}沒有逃逸的閉包的作用域是不會(huì)超過函數(shù)本身的,所以說我們不需要擔(dān)心在閉包內(nèi)持有self。逃逸的閉包就不同了,因?yàn)樾枰_保閉包內(nèi)的成員依然有效,如果在閉包內(nèi)引用self以及self的成員的話,就要考慮閉包內(nèi)持有self的情況了。

class S {

var foo = "foo"

func method1() {

doWork {

print(foo)

}

foo = "bar"

}

func method2() {

doWorkAsync {

print(self.foo)

}

foo = "bar"

}

func method3() {

doWorkAsync {

[weak self] _ in

print(self?.foo)

}

foo = "bar"

}

}

S().method1()// foo

S().method2()// bar

S().method3()// nil

method1不需要考慮self .foo的持有情況,而method2需要考慮,我們讓閉包持有了self,打印的值就是foo賦值之后的內(nèi)容bar,如果我們不希望閉包內(nèi)持有self的話,可以使用[weak self]的方法來表示. method3就是這樣,在閉包執(zhí)行的時(shí)候已經(jīng)沒有了對實(shí)例對象的引用,所有說輸出是nil。

weak 和 unowned

上面我用的是 [weak self] ,如果用[unowned self]表示的話,method3就需要稍做修改:

func method3() {

doWorkAsync {

[unowned self] _ in

print(self.foo)

}

foo = "bar"

}

這兩者都是用來防止循環(huán)引用的,但是還是有一點(diǎn)小小的區(qū)別:unowned 有點(diǎn)像oc里面的unsafe_unretained,而weak就是以前的weak。對于這兩者的使用,不能說用哪一個(gè)要好一點(diǎn),要視情況而定。用unowned的話,即使它原來的引用的內(nèi)容被釋放了,它仍然會(huì)保持對被已經(jīng)釋放了的對象的一個(gè)引用,它不能是Optional也不能是nil值,這個(gè)時(shí)候就會(huì)出現(xiàn)一個(gè)問題,如果你調(diào)用這個(gè)引用方法或者訪問成員屬性的話,就會(huì)出現(xiàn)崩潰。而weak要稍微友善一點(diǎn),在引用的內(nèi)容被釋放之后,會(huì)自動(dòng)將weak的成員標(biāo)記為nil。有人要說,既然這樣,那我全部使用weak。但是在可能的情況下,我們還是應(yīng)該傾向于盡量減少出現(xiàn)Optional 的可能性,這樣有助于代碼的簡化。Apple給我們的建議是如果能夠確定訪問時(shí)不會(huì)被釋放的話,盡量用unowned,如果存在被釋放的可能性的話,就用weak。

在Playground里面進(jìn)行異步操作

上面的代碼如果你在Playground里面運(yùn)行的話,你會(huì)發(fā)現(xiàn)method2,method3方法里面的回調(diào)不會(huì)走。不會(huì)走的原因大概是來不及走,三個(gè)函數(shù)一執(zhí)行完,程序就終止了,異步來不及執(zhí)行。怎么來解決這個(gè)問題呢?在Xcode 8 里面我們可以import PlaygroundSupport,在調(diào)用方法前設(shè)置PlaygroundPage.current.needsIndefiniteExecution = true就好了。

PlaygroundPage.current.needsIndefiniteExecution = true

S().method1()// foo

S().method2()// bar

S().method3()// nil

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

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

  • @escaping 在Swift3中,閉包默認(rèn)是非逃逸的。在Swift3之前,事情是完全相反的:那時(shí)候逃逸閉包是默...
    請叫我小陳陳閱讀 14,560評論 4 27
  • 1、范型范型所解決的問題 函數(shù)、方法、類型:類,結(jié)構(gòu)體,枚舉,元組類型,協(xié)議參數(shù),返回值,成員函數(shù)參數(shù),成員屬性類...
    我是小胡胡123閱讀 941評論 0 1
  • 在上一篇文章Swift中的變量和常量中我總結(jié)了一些自己對于變量和常量的認(rèn)識(shí),最近學(xué)習(xí)了閉包,順便給大家分享一下關(guān)于...
    老板娘來盤一血閱讀 18,875評論 16 87
  • 1、隨機(jī)數(shù) 不需要隨機(jī)數(shù)種子 arc4random()%N + begin:產(chǎn)生begin~begin+N的隨機(jī)數(shù)...
    我是小胡胡123閱讀 4,407評論 0 2
  • 漸漸走過時(shí)間的河 流淌著一段不被打擾的往事 斑駁陸離的影像訴說著時(shí)光的殤 一個(gè)沒有陽光的日子 訴說著這個(gè)世界的奄奄...
    岳讀閱讀 173評論 2 5

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