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

Swift中優(yōu)雅處理閉包導(dǎo)致的循環(huán)引用詳解

 更新時(shí)間:2019年08月06日 09:29:49   作者:小橘爺  
這篇文章主要給大家介紹了關(guān)于Swift中優(yōu)雅的處理閉包導(dǎo)致的循環(huán)引用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Swift具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

前言

Objective-C 作為一門資歷很老的語(yǔ)言,添加了 Block 這個(gè)特性后深受廣大 iOS 開發(fā)者的喜愛。在 Swift 中,對(duì)應(yīng)的概念叫做 Closure,即閉包。雖然更換了名字,但是概念和用法還是相似的,就算是副作用也一樣,有可能導(dǎo)致循環(huán)引用。

下面我們用一個(gè)例子看一下,首先我們需要第一個(gè)控制器(FirstViewController),它所做的就是簡(jiǎn)單的推出第二個(gè)控制器(SecondViewController)。

class FirstViewController: UIViewController {
 
 private let button: UIButton = {
  let button = UIButton()
  button.setTitleColor(UIColor.black, for: .normal)
  button.setTitle("跳轉(zhuǎn)到 SecondViewController", for: .normal)
  button.sizeToFit()
  return button
 }()
 
 override func viewDidLoad() {
  super.viewDidLoad()
  
  button.center = view.center
  view.addSubview(button)
  button.addTarget(self, action: #selector(buttonClick), for: .touchUpInside)
 }
 
 @objc private func buttonClick() {
  let secondViewController = SecondViewController()  
  navigationController?.pushViewController(secondViewController, animated: true)
 }
}

下面是 SecondViewController 的代碼。SecondViewController 所做的事情是推出第三個(gè)控制器(ThirdViewController),不同的是,thirdViewController 是作為一個(gè)屬性存在的,同時(shí)它還有一個(gè)閉包 closure ,這是我們用來測(cè)試循環(huán)引用問題的。還實(shí)現(xiàn)了 deinit 方法,用來打印一條語(yǔ)句,看該控制器是否被釋放了。

class SecondViewController: UIViewController {
 
 private let thirdViewController = ThirdViewController()
 private let button: UIButton = {
  let button = UIButton()
  button.setTitleColor(UIColor.black, for: .normal)
  button.setTitle("跳轉(zhuǎn)到 ThirdViewController", for: .normal)
  button.sizeToFit()
  return button
 }()
 
 override func viewDidLoad() {
  super.viewDidLoad()
  
  button.center = view.center
  view.addSubview(button)
  button.addTarget(self, action: #selector(buttonClick), for: .touchUpInside)
 }
 
 deinit {
  print("SecondViewController-被釋放了")
 }
 
 @objc private func buttonClick() {
  thirdViewController.closure = {
   self.test()
  }
  navigationController?.pushViewController(thirdViewController, animated: true)
 }
 
 private func test() {
  print("調(diào)用 test 方法")
 }
}

接下來我們看一下 ThirdViewController 的代碼。在 ThirdViewController 中有一個(gè)按鈕,點(diǎn)擊一下就會(huì)觸發(fā)閉包。同時(shí)我們還實(shí)現(xiàn)了 deinit 方法,用來打印一條語(yǔ)句,看該控制器是否被釋放了。

class ThirdViewController: UIViewController {
 
 private let button: UIButton = {
  let button = UIButton()
  button.setTitleColor(UIColor.black, for: .normal)
  button.setTitle("點(diǎn)擊按鈕", for: .normal)
  button.sizeToFit()
  return button
 }()
 
 var closure: (() -> Void)?
 
 override func viewDidLoad() {
  super.viewDidLoad()
  
  button.center = view.center
  view.addSubview(button)
  button.addTarget(self, action: #selector(buttonClick), for: .touchUpInside)
 }
 
 deinit {
  print("ThirdViewController-被釋放了")
 }
 
 @objc private func buttonClick() {
  closure?()
 }
}

當(dāng)我們連續(xù)推到第三個(gè)控制器,點(diǎn)擊按鈕(觸發(fā)閉包)后,再回到第一個(gè)控制器,看一下三個(gè)控制器的生命周期。當(dāng)流程走完后,發(fā)現(xiàn)控制臺(tái)只有一條語(yǔ)句:

調(diào)用 test 方法

這說明閉包已經(jīng)引起了循環(huán)引用問題,導(dǎo)致第二個(gè)控制器沒能被釋放(內(nèi)存泄漏)。正是因?yàn)殚]包會(huì)導(dǎo)致循環(huán)引用,所以在閉包中調(diào)用對(duì)象內(nèi)部的方法時(shí),都要顯式的使用 self,提醒我們要注意可能引起的內(nèi)存泄漏問題。與 Objective-C 不同的是,我們不需要在每一次使用閉包之前再繁瑣的寫上 __weak typeof(self) weakSelf = self; 了,取而代之的是捕獲列表的概念:

@objc private func buttonClick() { 
 thirdViewController.closure = { [weak self] in 
  self?.test()
 }
 navigationController?.pushViewController(thirdViewController, animated: true)
}

再重復(fù)一次上面的流程,可以看到控制臺(tái)多了兩條語(yǔ)句:

調(diào)用 test 方法
SecondViewController-被釋放了
ThirdViewController-被釋放了

只要在捕獲列表中聲明了你想要用弱引用的方式捕獲的對(duì)象,就可以及時(shí)的規(guī)避由閉包導(dǎo)致的循環(huán)引用了。但是同時(shí)可以看到,閉包中對(duì)于方法的調(diào)用從常規(guī)的 self.test() 變?yōu)榱丝蛇x鏈的 self?.test()。這是因?yàn)榧僭O(shè)閉包在子線程中執(zhí)行,執(zhí)行過程中 self 在主線程隨時(shí)有可能被釋放。由于 self 在閉包中成為了一個(gè)弱引用,因此會(huì)自動(dòng)變?yōu)?nil。在 Swift 中,可選類型的概念讓我們只能以可選鏈的方式來調(diào)用 test。下面修改一下 ThirdViewController 中的代碼:

@objc private func buttonClick() {
 // 模擬網(wǎng)絡(luò)請(qǐng)求
 DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + 5) {
  self.closure?()
 }
}

再次執(zhí)行相同的操作步驟,這次我們發(fā)現(xiàn) test 方法沒能正確的得到調(diào)用:

SecondViewController-被釋放了
ThirdViewController-被釋放了

在實(shí)際的項(xiàng)目中,這可能會(huì)導(dǎo)致一些問題,閉包中捕獲的 self 是 weak 的,有可能在閉包執(zhí)行的過程中就被釋放了,導(dǎo)致閉包中的一部分方法被執(zhí)行了而一部分沒有,應(yīng)用的狀態(tài)因此變得不一致。于是這個(gè)時(shí)候就要用到 Weak-Strong Dance 了。

既然知道了 self 在閉包中成為了可選類型,那么除了可選鏈,還可以使用可選綁定來處理可選類型:

@objc private func buttonClick() { 
 thirdViewController.closure = { [weak self] in 
  if let strongSelf = self {
   strongSelf.test()
  } else {
   // 處理 self 被釋放時(shí)的情況。
  }
 }
 navigationController?.pushViewController(thirdViewController, animated: true)
}

但這樣總是會(huì)讓我們?cè)陂]包中的代碼多出兩句甚至更多,于是還有更優(yōu)雅的方法,就是使用 guard 語(yǔ)句:

@objc private func buttonClick() { 
 thirdViewController.closure = { [weak self] in 
  guard let strongSelf = self else { return } 
  strongSelf.test()
 }
 navigationController?.pushViewController(thirdViewController, animated: true)
}

一句代碼搞定~

當(dāng)然,有人看到這里會(huì)說,每次都要使用 strongSelf 來調(diào)用 self 的方法,好煩啊……那么這一點(diǎn)還是可以進(jìn)一步被優(yōu)化的,Swift 與 Objective-C 不同,是可以使用部分關(guān)鍵字來聲明變量的,于是我們可以:

@objc private func buttonClick() { 
 thirdViewController.closure = { [weak self] in 
  guard let `self` = self else { return } 
  self.test()
 }
 navigationController?.pushViewController(thirdViewController, animated: true)
}

這樣就可以避免每次書寫 strongSelf 的煩躁感了~

原文地址:Weak-Strong Dance In Swift——如何在 Swift 中優(yōu)雅的處理閉包導(dǎo)致的循環(huán)引用

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Swift簡(jiǎn)單快速的動(dòng)態(tài)更換app圖標(biāo)AppIcon方法示例

    Swift簡(jiǎn)單快速的動(dòng)態(tài)更換app圖標(biāo)AppIcon方法示例

    這篇文章主要為大家介紹了Swift動(dòng)態(tài)更換app圖標(biāo)AppIcon的簡(jiǎn)單快速方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • iPhone與iWatch連接、控制、數(shù)據(jù)傳遞(Swift)的方法

    iPhone與iWatch連接、控制、數(shù)據(jù)傳遞(Swift)的方法

    這篇文章主要介紹了iPhone與iWatch連接、控制、數(shù)據(jù)傳遞(Swift)的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-03-03
  • Swift實(shí)現(xiàn)簡(jiǎn)單計(jì)算器項(xiàng)目

    Swift實(shí)現(xiàn)簡(jiǎn)單計(jì)算器項(xiàng)目

    這篇文章主要為大家詳細(xì)介紹了Swift實(shí)現(xiàn)簡(jiǎn)單計(jì)算器項(xiàng)目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Swift能代替Objective-C嗎?

    Swift能代替Objective-C嗎?

    這是我在網(wǎng)上上看到的答案,復(fù)制粘貼過來和大家分享一下,因?yàn)槲液秃芏嗳艘粯雍荜P(guān)心Swift的出現(xiàn)對(duì)Mac開發(fā)的影響和對(duì)Objective-C的影響。
    2014-09-09
  • 初探Swift3.0帶來的變化匯總

    初探Swift3.0帶來的變化匯總

    這個(gè)周末抽空看了下swift3.0的變化,今天小編通過本教程給大家分享Swift3.0帶來的變化,非常不錯(cuò),感興趣的朋友參考下吧
    2016-12-12
  • Swift中添加雙擊手勢(shì)識(shí)別器

    Swift中添加雙擊手勢(shì)識(shí)別器

    在這次IOS應(yīng)用開發(fā)教程中,我們打算實(shí)現(xiàn)手勢(shì)識(shí)別。正如你所知道的,IOS支持大量的手勢(shì)操作,它們能提供了很好的應(yīng)用控制和出色用戶體驗(yàn)。
    2019-08-08
  • Swift 圖表使用Foudation庫(kù)中測(cè)量類型詳解

    Swift 圖表使用Foudation庫(kù)中測(cè)量類型詳解

    這篇文章主要為大家介紹了Swift 圖表使用Foudation庫(kù)中測(cè)量類型詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Swift教程之集合類型詳解

    Swift教程之集合類型詳解

    這篇文章主要介紹了Swift教程之集合類型詳解,Swift 提供兩種集合類型來存儲(chǔ)集合,數(shù)組和字典,本文詳細(xì)講解了數(shù)組的創(chuàng)建、讀取和修改數(shù)組、遍歷數(shù)組以及集合的操作等內(nèi)容,需要的朋友可以參考下
    2015-01-01
  • 詳解Swift的switch...case語(yǔ)句中break關(guān)鍵字的用法

    詳解Swift的switch...case語(yǔ)句中break關(guān)鍵字的用法

    這篇文章主要介紹了Swift的switch...case語(yǔ)句中break關(guān)鍵字的用法,是Swift入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2016-04-04
  • Swift使用CollectionView實(shí)現(xiàn)廣告欄滑動(dòng)效果

    Swift使用CollectionView實(shí)現(xiàn)廣告欄滑動(dòng)效果

    這篇文章主要為大家詳細(xì)介紹了Swift使用CollectionView實(shí)現(xiàn)廣告欄滑動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06

最新評(píng)論

南通市| 灌阳县| 浏阳市| 富川| 当雄县| 怀宁县| 仪陇县| 溆浦县| 左云县| 塘沽区| 双柏县| 舒城县| 广灵县| 休宁县| 金湖县| 台安县| 建昌县| 陇川县| 格尔木市| 枣强县| 和政县| 庆城县| 恩平市| 正宁县| 泰顺县| 宜春市| 马山县| 陇川县| 南溪县| 永登县| 荣昌县| 巴青县| 富锦市| 连江县| 灯塔市| 台北市| 乌海市| 晋州市| 黄龙县| 开化县| 贺州市|