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

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

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

前言

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

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

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

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

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

在后一種情況下,我們談論的是轉(zhuǎn)義閉包;關閉該繼續(xù)即使電子住后的的xecution方法,直到我們在以后的任何時間在未來給他們打電話。

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

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

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

func  add(num1:  Double,

 num2:  Double,

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

    let  sum  =  num1  +  num2

    completion(sum)

}

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

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

逃離方法

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

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

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

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

resultHandler  =  completion

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

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

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

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

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

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

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 方法計算的結果加倍。但是,該結果不會翻倍,并且在add2(num1:num2:completion:)我們調(diào)用該getResult()方法之前,不會執(zhí)行該方法中閉包主體內(nèi)的代碼。

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

注意強參考周期

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

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

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

注意:當我們嘗試通過將對象設置為 nil 來釋放它時,可能存在內(nèi)存泄漏,但該對象仍保留在內(nèi)存中,因為該對象與其他保持其活動狀態(tài)的對象之間存在強引用。

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

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

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

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

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

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

Init

30.0

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

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

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

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

resultHandler  =  completion

這條線比看起來更“有罪”,因為它創(chuàng)建了對閉包的強烈引用completion。

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

然而,僅憑這一點還不足以產(chǎn)生問題,因為釋放demo實例會刪除對閉包的引用。真正的麻煩始于doubleSum(num1:num2:)方法內(nèi)部的閉包主體。

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

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

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

請注意,這僅發(fā)生在包含帶有轉(zhuǎn)義閉包的方法的類中。structs 的情況有所不同,因為它們不是引用而是值類型,并且顯式引用self不是強制性的。

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

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

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

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

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在關閉打開后查看添加。有了這個,我們建立了對 Demo 實例的弱引用,因此我們避免了保留循環(huán)。請注意,我們將self用作可選值,并在其后加上問號 (?) 符號。

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

Init

30.0

Deinit

概括

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

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

相關文章

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

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

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

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

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

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

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

    swift 錯誤處理do catch try try!使用詳解

    這篇文章主要介紹了swift 錯誤處理do catch try try!使用詳解的相關資料,需要的朋友可以參考下
    2023-03-03
  • 因為一個Crash引發(fā)對Swift構造器的思考分析

    因為一個Crash引發(fā)對Swift構造器的思考分析

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

    Swift能代替Objective-C嗎?

    這是我在網(wǎng)上上看到的答案,復制粘貼過來和大家分享一下,因為我和很多人一樣很關心Swift的出現(xiàn)對Mac開發(fā)的影響和對Objective-C的影響。
    2014-09-09
  • Swift實現(xiàn)倒計時5秒功能

    Swift實現(xiàn)倒計時5秒功能

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

    Swift與Objective C的簡單對比

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

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

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

    Swift中添加雙擊手勢識別器

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

最新評論

靖西县| 彭水| 谢通门县| 淮阳县| 汉源县| 浦县| 新乡市| 中牟县| 吉林市| 大名县| 滦平县| 镇康县| 日喀则市| 南充市| 遂宁市| 高青县| 平果县| 泰州市| 鄂尔多斯市| 青州市| 兖州市| 开化县| 麦盖提县| 甘南县| 牟定县| 共和县| 田东县| 丹东市| 林周县| 富阳市| 泾阳县| 厦门市| 汽车| 宁乡县| 寿阳县| 射洪县| 普兰店市| 昌黎县| 临沭县| 武山县| 东海县|