最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Swift中轉(zhuǎn)義閉包示例詳解

 更新時(shí)間:2021年11月03日 16:32:21   作者:小小小_小朋友  
在Swift 中的閉包類似于結(jié)構(gòu)塊,并可以在任何地方調(diào)用,下面這篇文章主要給大家介紹了關(guān)于Swift中轉(zhuǎn)義閉包的相關(guān)資料,需要的朋友可以參考下

前言

Swift 是一種非常強(qiáng)大的編程語言,是為 Apple 生態(tài)系統(tǒng)開發(fā)應(yīng)用程序的首選;iOS、macOS、watchOS 和 tvOS。作為使用 Swift 編寫代碼的開發(fā)人員,我們經(jīng)常使用閉包;語言的一個(gè)重要而重要的章節(jié)。

閉包不是初學(xué)者開始的主題。然而,這是每個(gè)人都必須盡快了解的東西。有很多方面需要了解并了解它們的工作原理。在所有這些中,有一個(gè)特定的;轉(zhuǎn)義閉包和@escaping屬性。在這篇文章中,我將盡可能簡單地解釋它們是什么以及它們可能帶來的附帶影響。

轉(zhuǎn)義與非轉(zhuǎn)義閉包

在談?wù)撧D(zhuǎn)義閉包時(shí),我們總是指作為函數(shù)或方法參數(shù)提供的閉包。一般來說,我們將提供給方法(或函數(shù))的閉包分為兩類:

  1. 在方法執(zhí)行完成之前調(diào)用的閉包。
  2. 在方法執(zhí)行完成后調(diào)用的閉包。

在后一種情況下,我們談?wù)摰氖寝D(zhuǎn)義閉包;關(guān)閉該繼續(xù)即使電子住后的的xecution方法,直到我們在以后的任何時(shí)間在未來給他們打電話。

在前一種情況下,與我上面描述的完全相反,我們稱閉包為non-escaping。

直到 Swift 3,默認(rèn)情況下,所有作為參數(shù)傳遞給方法或函數(shù)的閉包都被認(rèn)為是轉(zhuǎn)義的。自 Swift 3 以來,這不再正確;默認(rèn)情況下,所有方法都被認(rèn)為是非轉(zhuǎn)義的,這意味著它們在方法執(zhí)行完成之前被調(diào)用。

以下代碼部分演示了一個(gè)非轉(zhuǎn)義閉包:

func  add(num1:  Double,

 num2:  Double,

 completion:  (_  result:  Double)  ->  Void)  {

    let  sum  =  num1  +  num2

    completion(sum)

}

所述completion封閉件之前執(zhí)行代碼葉調(diào)用的方法,所以這不是一個(gè)逸出閉合的情況。

然而,一個(gè)閉包是如何從一個(gè)方法中逃脫的,所以我們最終得到了與上述情況相反的結(jié)果?

逃離方法

為了使閉包成為轉(zhuǎn)義閉包,有必要將對其的引用保留在方法的范圍之外,以便我們稍后使用它??纯聪旅娴拇a:

class  Demo  {  
    var  result:  Double?
    var  resultHandler:  (()  ->  Void)?
    func  add2(num1:  Double,
              num2:  Double,
              completion:  ()  ->  Void)  {
        resultHandler  =  completion
        result  =  num1  +  num2
    }
}

這里我們有一個(gè)result屬性,它保存在方法內(nèi)部發(fā)生的加法的結(jié)果。但我們也resultHandler有財(cái)產(chǎn);this 保持對completion作為方法參數(shù)提供的閉包的引用。

閉包通過以下行從方法中轉(zhuǎn)義:

resultHandler  =  completion

然而,這不是唯一需要的操作,所以我們可以說這completion是一個(gè)轉(zhuǎn)義閉包。我們必須明確指出編譯器,否則我們將在 Xcode 中看到以下錯(cuò)誤:

為了修復(fù)它,我們需要用@escaping屬性標(biāo)記閉包。我們將此屬性放在閉包名稱和分號之后,但在閉包類型之前,如下所示:

func  add2(num1:  Double,
          num2:  Double,
          completion:  @escaping  ()  ->  Void)  {
    ...
}

編譯器不再抱怨,completion現(xiàn)在正式成為轉(zhuǎn)義閉包。

將轉(zhuǎn)義關(guān)閉付諸行動

讓我們在上面的Demo類中再添加兩個(gè)方法;一個(gè)將調(diào)用add2(num1:num2:completion:)方法,另一個(gè)將調(diào)用resultHandler閉包以獲得最終結(jié)果:

class  Demo  {
    ...
    func  doubleSum(num1:  Double,
                    num2:  Double)  {
        add2(num1:  num1,  num2:  num2)  {
            guard let  result  =  self.result  else  {  return  }
            self.result  =  result  *  2
        }
    }

    func  getResult()  {
        resultHandler?()
    }
}

第一種方法將 add 方法計(jì)算的結(jié)果加倍。但是,該結(jié)果不會翻倍,并且在add2(num1:num2:completion:)我們調(diào)用該getResult()方法之前,不會執(zhí)行該方法中閉包主體內(nèi)的代碼。

這是我們從轉(zhuǎn)義閉包中受益的地方;我們可以在我們的代碼中需要的時(shí)候以及在合適的時(shí)機(jī)觸發(fā)閉包的調(diào)用。盡管提供的示例故意過于簡單,但在實(shí)際項(xiàng)目中,實(shí)際優(yōu)勢會變得更加明顯和大膽。

注意強(qiáng)參考周期

讓我們?yōu)镈emo類添加最后一個(gè),并實(shí)現(xiàn)默認(rèn)的初始化器和析構(gòu)器方法:

class  Demo  {
    init()  {
        print("Init")
    }
    deinit  {
        print("Deinit")
    }
    ...
}

init()是Demo初始化實(shí)例時(shí)調(diào)用的第一個(gè)方法,deinit也是釋放實(shí)例之前調(diào)用的最后一個(gè)方法。我向它們都添加了一個(gè)打印命令,以驗(yàn)證它們是否被調(diào)用,并且在使用帶有上述轉(zhuǎn)義閉包的方法時(shí)沒有內(nèi)存泄漏。

注意:當(dāng)我們嘗試通過將對象設(shè)置為 nil 來釋放它時(shí),可能存在內(nèi)存泄漏,但該對象仍保留在內(nèi)存中,因?yàn)樵搶ο笈c其他保持其活動狀態(tài)的對象之間存在強(qiáng)引用。

現(xiàn)在,讓我們添加以下幾行來使用上述所有內(nèi)容:

var  demo:  Demo?  =  Demo()
demo?.doubleSum(num1:  5,  num2:  10)
demo?.getResult()
print((demo?.result!)!)
demo  =  nil

首先,我們初始化類的一個(gè)可選實(shí)例Demo,以便稍后我們可以將其設(shè)為 nil。然后,我們調(diào)用該doubleSum(num1:num2:)方法以將作為參數(shù)給出的兩個(gè)數(shù)字相加,然后將該結(jié)果加倍。但是,正如我之前所說的,在我們調(diào)用該getResult()方法之前不會發(fā)生這種情況;在方法中實(shí)際調(diào)用轉(zhuǎn)義閉包的那個(gè)add2(num1:num2:completion:)。

最后,我們打印實(shí)例中result屬性的值demo,并將其demo設(shè)為 nil。

*注意:*如上面的代碼片段所示,使用感嘆號 (!) 強(qiáng)制展開可選值是一種非常糟糕的做法,請不要這樣做。我在這里這樣做的唯一原因是為了讓事情盡可能簡單。

以上行將打印以下內(nèi)容:

Init

30.0

請注意,此處缺少“Deinit”消息!也就是說deinit沒有調(diào)用該方法,證明制作demo實(shí)例nil沒有實(shí)際結(jié)果。看起來,只需幾行簡單的代碼,我們就設(shè)法解決了內(nèi)存泄漏問題。

內(nèi)存泄漏背后的原因

在我們找到解決內(nèi)存泄漏的方法之前,有必要了解它發(fā)生的原因。為了找到它,讓我們退后幾步來修改我們之前所做的。

首先,我們使用以下completion行使閉包從方法中逃逸:

resultHandler  =  completion

這條線比看起來更“有罪”,因?yàn)樗鼊?chuàng)建了對閉包的強(qiáng)烈引用completion。

注意:閉包是引用類型,就像類一樣。

然而,僅憑這一點(diǎn)還不足以產(chǎn)生問題,因?yàn)獒尫興emo實(shí)例會刪除對閉包的引用。真正的麻煩始于doubleSum(num1:num2:)方法內(nèi)部的閉包主體。

在那里,我們這次通過在使用對象訪問屬性時(shí)捕獲**對象來創(chuàng)建另一個(gè)從閉包到demo實(shí)例的強(qiáng)引用:selfresult

guard let  result  =  self.result  else  {  return  }
self.result  =  result  *  2

當(dāng)它們都到位時(shí),Demo 實(shí)例保持對閉包的強(qiáng)引用,而閉包則是對實(shí)例的強(qiáng)引用。這會創(chuàng)建一個(gè)保留循環(huán),也稱為強(qiáng)引用循環(huán)。發(fā)生這種情況時(shí),每個(gè)引用類型都會使另一個(gè)引用類型在內(nèi)存中保持活動狀態(tài),因此它們最終都不會被釋放。

請注意,這僅發(fā)生在包含帶有轉(zhuǎn)義閉包的方法的類中。structs 的情況有所不同,因?yàn)樗鼈儾皇且枚侵殿愋?,并且顯式引用self不是強(qiáng)制性的。

消除強(qiáng)引用循環(huán)

有兩種方法可以避免強(qiáng)引用循環(huán),從而避免內(nèi)存泄漏。第一個(gè)是在我們調(diào)用閉包后手動且顯式地釋放對閉包的引用:

func  getResult()  {
    resultHandler?()
    // Setting nil to resultHandler removes the reference to closure.
    resultHandler  =  nil
}

第二種方法是在閉包的主體中弱**捕獲self實(shí)例:

func  doubleSum(num1:  Double,
 num2:  Double)  {
    add2(num1:  num1,  num2:  num2)  {  [weak  self]  in
        guard let  result  =  self?.result  else  {  return  }
        self?.result  =  result  *  2
    }
}

[weak self] in在關(guān)閉打開后查看添加。有了這個(gè),我們建立了對 Demo 實(shí)例的弱引用,因此我們避免了保留循環(huán)。請注意,我們將self用作可選值,并在其后加上問號 (?) 符號。

沒有必要應(yīng)用這兩種更改以避免強(qiáng)引用循環(huán)。無論我們最終選擇哪一個(gè),從現(xiàn)在開始,輸出也將包含“Deinit”消息。這意味著該demo對象變?yōu)?nil,并且我們不再有內(nèi)存泄漏。

Init

30.0

Deinit

概括

離開這里需要帶上一件事,那就是在使用轉(zhuǎn)義閉包時(shí)要小心。無論您是實(shí)現(xiàn)自己的接受轉(zhuǎn)義閉包作為參數(shù)的方法,還是使用具有轉(zhuǎn)義閉包的 API,請始終確保不會以強(qiáng)引用循環(huán)結(jié)束。在開發(fā)應(yīng)用程序時(shí),內(nèi)存泄漏是一個(gè)很大的“禁忌”,我們當(dāng)然不希望我們的應(yīng)用程序在某個(gè)時(shí)候崩潰或因此被系統(tǒng)終止。另一方面,不要猶豫使用轉(zhuǎn)義閉包;它們提供了可以產(chǎn)生更強(qiáng)大代碼的優(yōu)勢。

到此這篇關(guān)于Swift中轉(zhuǎn)義閉包的文章就介紹到這了,更多相關(guān)Swift轉(zhuǎn)義閉包內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Swift中的可變參數(shù)函數(shù)介紹

    Swift中的可變參數(shù)函數(shù)介紹

    這篇文章主要介紹了Swift中的可變參數(shù)函數(shù)介紹,本文實(shí)現(xiàn)了和Objective-C調(diào)用方法一樣的變參數(shù)函數(shù),需要的朋友可以參考下
    2015-01-01
  • swift指針及內(nèi)存管理內(nèi)存綁定實(shí)例詳解

    swift指針及內(nèi)存管理內(nèi)存綁定實(shí)例詳解

    這篇文章主要為大家介紹了swift指針及內(nèi)存管理內(nèi)存綁定實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • RxSwift使用技巧之過濾操作詳解

    RxSwift使用技巧之過濾操作詳解

    RxSwift的目的是讓讓數(shù)據(jù)/事件流和異步任務(wù)能夠更方便的序列化處理,能夠使用Swift進(jìn)行響應(yīng)式編程,下面這篇文章主要給大家介紹了關(guān)于RxSwift使用技巧之過濾操作的相關(guān)資料,需要的朋友可以參考下。
    2017-09-09
  • swift 錯(cuò)誤處理do catch try try!使用詳解

    swift 錯(cuò)誤處理do catch try try!使用詳解

    這篇文章主要介紹了swift 錯(cuò)誤處理do catch try try!使用詳解的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • 因?yàn)橐粋€(gè)Crash引發(fā)對Swift構(gòu)造器的思考分析

    因?yàn)橐粋€(gè)Crash引發(fā)對Swift構(gòu)造器的思考分析

    這篇文章主要給大家介紹了關(guān)于因?yàn)橐粋€(gè)Crash引發(fā)對Swift構(gòu)造器的思考分析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用Swift具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Swift能代替Objective-C嗎?

    Swift能代替Objective-C嗎?

    這是我在網(wǎng)上上看到的答案,復(fù)制粘貼過來和大家分享一下,因?yàn)槲液秃芏嗳艘粯雍荜P(guān)心Swift的出現(xiàn)對Mac開發(fā)的影響和對Objective-C的影響。
    2014-09-09
  • Swift實(shí)現(xiàn)倒計(jì)時(shí)5秒功能

    Swift實(shí)現(xiàn)倒計(jì)時(shí)5秒功能

    這篇文章主要為大家詳細(xì)介紹了Swift實(shí)現(xiàn)倒計(jì)時(shí)5秒功能,在“登錄”和“注冊”頁面也有相似功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • Swift與Objective C的簡單對比

    Swift與Objective C的簡單對比

    很多人想學(xué)習(xí)iOS開發(fā),但是不知道如何從Objective-C和Swift之間選擇。而網(wǎng)上的一些答案,大抵說的是,以后Swift終將取代Objective-C,但是目前來講還是Objective-C比較重要。那么究竟怎樣呢,今天我們就來探討下
    2016-12-12
  • Swift利用純代碼實(shí)現(xiàn)時(shí)鐘效果實(shí)例代碼

    Swift利用純代碼實(shí)現(xiàn)時(shí)鐘效果實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于Swift利用純代碼實(shí)現(xiàn)時(shí)鐘效果的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用swift具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-05-05
  • Swift中添加雙擊手勢識別器

    Swift中添加雙擊手勢識別器

    在這次IOS應(yīng)用開發(fā)教程中,我們打算實(shí)現(xiàn)手勢識別。正如你所知道的,IOS支持大量的手勢操作,它們能提供了很好的應(yīng)用控制和出色用戶體驗(yàn)。
    2019-08-08

最新評論

乌拉特后旗| 潜山县| 花莲县| 石首市| 石首市| 皋兰县| 英超| 双流县| 敖汉旗| 平舆县| 长顺县| 深泽县| 明光市| 铅山县| 大港区| 江源县| 清水河县| 沭阳县| 洛南县| 崇文区| 武平县| 长乐市| 碌曲县| 海城市| 凌海市| 太白县| 都兰县| 剑川县| 泌阳县| 保德县| 泽普县| 买车| 永兴县| 彩票| 长葛市| 唐海县| 延津县| 天峨县| 新沂市| 修武县| 石渠县|