麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > Swift > 正文

Swift中如何避免循環(huán)引用的方法

2020-03-09 17:42:57
字體:
供稿:網(wǎng)友

內(nèi)存管理中經(jīng)常會遇到的一個問題便是循環(huán)引用。首先,我們來了解一下iOS是如何進(jìn)行內(nèi)存管理的。

和OC一樣,swift也是使用自動引用計數(shù)ARC(Auto Reference Counteting)來自動管理內(nèi)存的,所以我們不需要過多考慮內(nèi)存管理.當(dāng)某個類實例不需要用到的時候,ARC會自動釋放其占用的內(nèi)存.

ARC

ARC(Automatic Reference Counting) 是蘋果的自動內(nèi)存管理機制。正如其名:自動引用計數(shù),根據(jù)引用計數(shù)來決定內(nèi)存塊是否應(yīng)該被釋放。

當(dāng)一個對象被創(chuàng)建的時候,它的引用計數(shù)為1。在它的生命周期內(nèi),其引用計數(shù)可以增加或減少。當(dāng)它的引用計數(shù)減為0的時候,其所占用內(nèi)存便會被釋放。其生命周期如圖所示:

Swift,避免循環(huán)引用

強引用和弱引用(Strong/Weak References)

定義一個變量的時候可以聲明其strong和weak屬性,默認(rèn)是strong類型。

struct Example { var strongView = UIView() weak var weakView = UIView()}

強引用和弱引用有什么不同呢?

強引用會使變量的引用計數(shù)加1。如果一個對象的引用計數(shù)為2,當(dāng)它再次被強引用的時候,它的引用計數(shù)會變?yōu)?。

弱引用不會增加引用計數(shù)。如果一個對象的引用計數(shù)為2,當(dāng)它再次被弱引用的時候,它的引用計數(shù)仍為2。

強引用的對象能保證其被調(diào)用的時候仍在內(nèi)存中,而弱引用不行。

循環(huán)引用和內(nèi)存泄漏

當(dāng)A引用B中的成員變量,而B又對A中的成員變量有引用的時候就會發(fā)生循環(huán)引用。
比如:

class Book { private var pages = [Page]()  func add(_ page : Page) {  pages.append(page) }}class Page { private var book : Book required init(book : Book) {  self.book = book }}let book = Book()let page = Page(book: book)book.add(page)

此時,book對page有強引用,同時page對book也有強引用。這個時候便有循環(huán)引用,會導(dǎo)致內(nèi)存泄漏。

對于這種兩個變量的相互強引用導(dǎo)致的內(nèi)存泄漏該如何解決呢?

Structs 和 Classes

正確的使用struct 和 class能避免循環(huán)引用的發(fā)生。

struct 和 class 都有成員變量,函數(shù)和協(xié)議。那么,它們之間有什么區(qū)別呢?

struct 是 值類型。
class 是 引用類型。

當(dāng)引用或者傳遞 值類型 變量的時候,它會在內(nèi)存中重新分配地址,copy內(nèi)容到新的地址中。

struct Element { var name : String var number : Int}var firstElement = Element(name: "A", number: 1)var secondElement = firstElementsecondElement.name = "B"secondElement.number = 2print(firstElement)print(secondElement)

輸出的結(jié)果為:

Element(name: “A”, number: 1)Element(name: “B”, number: 2)

當(dāng)引用或者傳遞 引用類型 變量的時候,新的變量指針指向的仍是原先的內(nèi)存地址。此時原先的變量值改變的話,也會導(dǎo)致新變量值的變化。

比如:

class Element { var name : String var number : Int  required init(name : String, number : Int) {  self.name = name  self.number = number }}extension Element : CustomStringConvertible { var description : String {  return "Element(name: /(name), number: /(number))" }}var firstElement = Element(name: "A", number: 1)var secondElement = firstElementsecondElement.name = "B"secondElement.number = 2print(firstElement)print(secondElement)

此時的輸出結(jié)果為:

Element(name: B, number: 2)Element(name: B, number: 2)

我們?yōu)槭裁丛诖擞懻撝殿愋秃鸵妙愋湍兀?/p>

回到之前book和pages的例子。我們用struct代替class:

struct Book { private var pages = [Page]()  mutating func add(_ page : Page) {  pages.append(page) }}struct Page { private var book : Book  init(book : Book) {  self.book = book }}var book = Book()let page = Page(book: book)book.add(page)

此時,便不會發(fā)生循環(huán)引用的情況。

如果仍想使用class的話,可以使用weak來避免循環(huán)引用:

class Book { private var pages = [Page]()  func add(_ page : Page) {  pages.append(page) }}class Page { private weak var book : Book?  required init(book : Book) {  self.book = book }}let book = Book()let page = Page(book: book)book.add(page)

Protocols

Protocols在swift中使用的很廣泛。class,struct 和 enum 都可以使用Protocol。但是如果使用不當(dāng)?shù)脑挘瑯訒鹧h(huán)引用。

比如:

protocol ListViewControllerDelegate { func configure(with list : [Any])}class ListViewController : UIViewController {  var delegate : ListViewControllerDelegate?  override func viewDidLoad() {  super.viewDidLoad() } }

ListViewController 中的delegate變量是strong類型的,可以引用任何實現(xiàn)它protocol的變量。假如實現(xiàn)其protocol的變量對該 view controller 同樣有強引用的話會怎么樣? 聲明delegate為weak可能會避免這種情況,但是這樣的話會引起編譯錯誤,因為structs和enums不能引用weak變量。

該如何解決呢?當(dāng)聲明protocol的時候,我們可以指定只有class類型的變量可以代理它,這樣的話就可以使用weak來修飾了。

protocol ListViewControllerDelegate : class { func configure(with list : [Any])}class ListViewController : UIViewController {  weak var delegate : ListViewControllerDelegate?  override func viewDidLoad() {  super.viewDidLoad() } }

Closures

Closures 導(dǎo)致循環(huán)引用的原因是:Closures對使用它們的對象有一個強引用。

比如:

class Example { private var counter = 0  private var closure : (() -> ()) = { }  init() {  closure = {   self.counter += 1   print(self.counter)  } }  func foo() {  closure() } }

此時,對象對closure有一個強引用,同時在closure的代碼塊中又對該對象本身有一個強引用。這樣就引起了循環(huán)引用的發(fā)生。

這種情況,可以有兩種方法來解決這個問題。

1.使用[unowned self]:

class Example { private var counter = 1  private var closure : (() -> ()) = { }  init() {  closure = { [unowned self] in   self.counter += 1   print(self.counter)  } }  func foo() {  closure() } }

使用[unowned self] 的時候需要注意的一點是:調(diào)用closure的時候如果對象已經(jīng)被釋放的話,會出現(xiàn)crash。

2.使用[weak self]:

class Example { private var counter = 1  private var closure : (() -> ()) = { }  init() {  closure = { [weak self] in   self?.counter += 1   print(self?.counter ?? "")  } }  func foo() {  closure() } }

[weak self] 和[unowned self] 的區(qū)別是 [weak self]處理的時候是一個可選類型。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到swift教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 午夜性久久 | 欧美一级三级在线观看 | 久久久免费观看完整版 | 欧美精品18 | 粉嫩av一区二区三区四区在线观看 | 日本精品久久久一区二区三区 | 亚洲免费视 | 一级视频网站 | 亚洲一区二区三区四区精品 | 亚洲小视频在线观看,com | 在线观看免费毛片视频 | 亚洲精品wwww | 日韩精品中文字幕在线观看 | 蜜桃av网| 国产精品高潮视频 | 国产精品福利一区 | 午夜热门福利 | 婷婷亚洲一区二区三区 | 国产亚洲精品久久久久久网站 | 羞羞视频免费入口网站 | 一级做a爱片久久毛片a高清 | 九九热在线视频免费观看 | 亚洲综合无码一区二区 | 本站只有精品 | 国产91大片| 国产精品久久久久久久久久久久午夜 | 福利免费在线观看 | 亚洲一区二区三区精品在线观看 | 亚洲精品成人在线视频 | 久久精品性视频 | japanesexxxxxxxhd | av黄色在线免费观看 | 毛片免费观看视频 | 精品国产乱码久久久久久丨区2区 | 欧美亚洲综合在线 | 欧美成人黄色小视频 | 黄色毛片视频在线观看 | 欧美日韩一 | 国产精选电影免费在线观看网站 | 国产精品成人免费一区久久羞羞 | 国产精品7区 |