你要知道的Swift閉包

前言

Swift的閉包在capture變量時(shí)隅熙,跟oc的還是有些區(qū)別的遍愿。下面來(lái)講講奔滑。

一覽Swift的閉包

在closure中使用外部變量耙考,swift默認(rèn)會(huì)capture該變量的reference谜喊,之后會(huì)細(xì)說(shuō)。為了避免在閉包執(zhí)行時(shí)琳骡,變量釋放锅论,所以會(huì)retain該變量讼溺。來(lái)看個(gè)例子楣号。

Animal類(lèi)。

class Animal:CustomDebugStringConvertible {
    let name: String
    init(name: String) {
        self.name = name
    }

    var debugDescription: String {
        return "<Animal \(name)>"
    }
    deinit {
        print("\(self) dealloc")
    }
}

delay函數(shù)

func delay(seconds: NSTimeInterval, closure: ()->()) {

    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))

    dispatch_after(time, dispatch_get_main_queue()) {
        closure()
    }
}
func demo1() {
    let animal = Animal(name: "cat")
    print("before closure:\(animal)")

    delay(1) {
        // retain animal
        print("inside closure:\(animal)")
    }

    print("bye")
}

output:

 before closure:<Animal cat>
 bye
 inside closure:<Animal cat>
 <Animal cat> dealloc

這里怒坯,我們用dispatch_after延遲執(zhí)行一個(gè)閉包炫狱。當(dāng)demo1執(zhí)行完后,animal是還沒(méi)有dealloc的剔猿,因?yàn)楸婚]包retain了视译。只有當(dāng)閉包執(zhí)行完后,才會(huì)釋放掉归敬。

好了酷含。知道了上述理論后,來(lái)看看剛剛提到的reference汪茧。

reference

閉包默認(rèn)持有變量的reference椅亚,而不是變量本身。什么意思呢舱污?看個(gè)例子呀舔。請(qǐng)注意inside closure打印的那行

// caputure value evaluted when closure is executed
func demo2() {
    var animal = Animal(name: "cat")
    print("before closure:\(animal)")

    delay(1) { 
        print("inside closure:\(animal)")
    }

    animal = Animal(name: "dog")
    print("after closure:\(animal)")
}

ouput:

 before closure:<Animal cat>
 <Animal cat> dealloc
 after closure:<Animal dog>
 inside closure:<Animal dog>
 <Animal dog> dealloc

是不是覺(jué)得有點(diǎn)奇怪扩灯?這就是持有reference的作用媚赖。
可以看成其持有的是指向animal的指針p,即使animal所指向的obj在變珠插,但其實(shí)p的指針是始終不變的惧磺。看2張圖應(yīng)該就明白了捻撑。

p就是圖中的reference豺妓。

cat.png
dog.png

如果熟悉c的指針的話(huà)惜互,跟下面的代碼意思類(lèi)似。

char a = 'a';
char *p1 = &a;

char **p2 = &p1;
printf("%c", **p2);

char b = 'b';
p1 = &b;

// 此時(shí)**p2的值會(huì)為'b'琳拭,雖然p1的指向在變训堆,但p2-->p1的指向關(guān)系始終不變
printf("%c", **p2);

除了reference之外,還有提到的是白嘁。

1)capture的變量在閉包執(zhí)行的時(shí)候才計(jì)算坑鱼。

在這個(gè)例子中,我們修改了animal為dog絮缅,閉包中打印的也是成了dog鲁沥。

如果改成這樣,猜猜會(huì)打印出什么耕魄?

delay(1) { 
        animal = Animal(name:"duck")
        print("inside closure:\(animal)")
    }
  1. animal的dealloc画恰。在demo2執(zhí)行完后,cat就dealloc了吸奴。而dog還被持有允扇。看上圖则奥,animal--->cat之前的關(guān)聯(lián)已經(jīng)斷了考润,所以會(huì)dealloc,而此時(shí)animal指向了dog读处,所以dog仍會(huì)等到閉包執(zhí)行完后銷(xiāo)毀糊治。

value type

那么對(duì)于值類(lèi)型的捕獲呢,是否不一樣罚舱?很遺憾井辜,仍然是reference。意思是:不是簡(jiǎn)單的捕獲當(dāng)前的值管闷,存起來(lái)粥脚,亙古不變了。跟上面一樣渐北,value變了之后阿逃,閉包中的值跟著變。

func demo3() {
    var a = 40
    print("before closure:\(a)")
    delay(1) { 
        print("inside closure:\(a)")
    }

    a = 50
    print("after closure:\(a)")
}

output:

 before closure:40
 after closure:50
 inside closure:50
value.png

在閉包中修改值

可以在直接閉包中修改捕獲的值赃蛛,并且后續(xù)獲取到的就是新值恃锉。仍然是reference的功勞。而在oc中呕臂,需要聲明為_(kāi)_block破托。

func demo4() {
    var a = 40
    print("before closure:\(a)")
    delay(1) {
        print("inside closure1, before change:\(a)")
        a = 60
        print("inside closure1, after change:\(a)")
    }

    delay(2) {
        print("inside closure2:\(a)")
    }
}

如何做到和oc的捕獲一樣

如果只想capture變量在創(chuàng)建閉包時(shí)的值,使用capture list歧蒋。它會(huì)copy一份變量土砂,而非采用reference的方式州既。或者先聲明個(gè)變量 let copyValue = a萝映,跟capture list效果一樣吴叶。

func demo5() {
    var a = 40
    print("before closure:\(a)")
    
    let copyValue = a
    delay(1) { [constantValue = a] in
        print("inside closure:\(constantValue)")
        print("inside closure:\(copyValue)")
    }

    a = 50
    print("after closure:\(a)")
}

同樣對(duì)于class類(lèi)型的,也一樣

func demo6() {
    var animal = Animal(name: "cat")
    print("before closure:\(animal)")

    let animalCopy = animal

    delay(1) { [constantAnimal = animal] in
        print("inside closure constantAnimal:\(constantAnimal)")
        print("inside closure constantAnimal:\(animalCopy)")
    }

    animal = Animal(name: "dog")
    print("after closure:\(animal)")
}

終極混合

來(lái)個(gè)各種混合的序臂。

func demo7() {
    var animal = Animal(name: "cat")
    print("before closure:\(animal)")

    delay(1) { [constantAnimal = animal] in
        print("inside closure1 constantAnimal:\(constantAnimal)")
        print("inside closure1:\(animal)")

        animal = Animal(name: "snake")
        print("inside closure1 animal changed:\(animal)")
    }

    animal = Animal(name: "dog")
    print("animal changed:\(animal)")

    delay(2) { [constantAnimal = animal] in
        print("inside closure2 constantAnimal:\(constantAnimal)")
        print("inside closure2:\(animal)")

        animal = Animal(name: "bear")
        print("inside closure2 animal changed:\(animal)")
    }
}

看看會(huì)是神馬結(jié)果蚌卤??

后語(yǔ)

  1. swift閉包默認(rèn)持有變量的reference
  2. swift閉包默認(rèn)在執(zhí)行時(shí)才計(jì)算捕獲變量的值
  3. 可在swift閉包中修改捕獲變量的值
  4. 使用capture list奥秆,做變量的constant copy捕獲逊彭。

原文在此

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市构订,隨后出現(xiàn)的幾起案子侮叮,更是在濱河造成了極大的恐慌,老刑警劉巖悼瘾,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件囊榜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡分尸,警方通過(guò)查閱死者的電腦和手機(jī)锦聊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)歹嘹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)箩绍,“玉大人,你說(shuō)我怎么就攤上這事尺上〔闹耄” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵怎抛,是天一觀的道長(zhǎng)卑吭。 經(jīng)常有香客問(wèn)我,道長(zhǎng)马绝,這世上最難降的妖魔是什么豆赏? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮富稻,結(jié)果婚禮上掷邦,老公的妹妹穿的比我還像新娘。我一直安慰自己椭赋,他們只是感情好抚岗,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著哪怔,像睡著了一般宣蔚。 火紅的嫁衣襯著肌膚如雪向抢。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天胚委,我揣著相機(jī)與錄音挟鸠,去河邊找鬼。 笑死亩冬,一個(gè)胖子當(dāng)著我的面吹牛兄猩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鉴未,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼枢冤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了铜秆?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤连茧,失蹤者是張志新(化名)和其女友劉穎核蘸,沒(méi)想到半個(gè)月后啸驯,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡罚斗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了针姿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡距淫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出榕暇,到底是詐尸還是另有隱情蓬衡,我是刑警寧澤彤枢,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站堂污,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏盟猖。R本人自食惡果不足惜换棚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望反镇。 院中可真熱鬧,春花似錦歹茶、人聲如沸夕玩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)燎孟。三九已至,卻和暖如春尸昧,著一層夾襖步出監(jiān)牢的瞬間揩页,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工烹俗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留爆侣,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓幢妄,卻偏偏與公主長(zhǎng)得像兔仰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蕉鸳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 以下翻譯自Apple官方文檔乎赴,結(jié)合自己的理解記錄下來(lái)。翻譯基于 swift 3.0.1 原文地址 Closure...
    藝術(shù)農(nóng)閱讀 1,514評(píng)論 0 3
  • 本章將會(huì)介紹 閉包表達(dá)式尾隨閉包值捕獲閉包是引用類(lèi)型逃逸閉包自動(dòng)閉包枚舉語(yǔ)法使用Switch語(yǔ)句匹配枚舉值關(guān)聯(lián)值原...
    寒橋閱讀 1,552評(píng)論 0 3
  • 閉包是自包含的函數(shù)代碼塊缔赠,可以在代碼中被傳遞和使用衍锚。Swift 中的閉包與 C 和 Objective-C 中的代...
    窮人家的孩紙閱讀 1,697評(píng)論 1 5
  • 我喜歡書(shū)法與盆景 但我特別喜歡寫(xiě)單字 如:龍、虎嗤堰、鳯戴质、舞、……等踢匣! 今睌寫(xiě)個(gè)虎字 發(fā)扵愛(ài)好書(shū)法的友人 共同交流學(xué)習(xí)告匠!
    老武家閱讀 4,097評(píng)論 2 4
  • 二階段 片段一 《作業(yè)》 I:有效的對(duì)話(huà)尤其是和上司應(yīng)該是從結(jié)論開(kāi)始的,這種對(duì)話(huà)的方式有三種离唬,1后专、用習(xí)慣性的說(shuō)話(huà)方...
    麥冬1108閱讀 199評(píng)論 1 0