自動引用計數

  1. 使用弱引用解決循環強引用
    如果兩個變量屬性都可以設置爲nil,那麼就用弱引用來設置其中一個屬性來解決循環強引用。
class Person {
    let name: String
    init(name: String) {
        self.name = name
    }
    weak var apartment: Apartment?
    
    deinit {
        print("Person deinit")
    }
}

class Apartment {
    var unit: String
    var person: Person
    
    init(unit: String, person: Person) {
        self.unit = unit
        self.person = person
    }
    
    deinit {
        print("Apartment deinit")
    }
}


var aPerson: Person? = Person(name: "小明")
var aApartment: Apartment? = Apartment(unit: "豪宅",person: aPerson!)
aPerson!.apartment = aApartment

aPerson = nil
aApartment = nil
  1. 無主引用
    如果兩個變量屬性,其中一個可以設置成nil,另一個必須有值。那麼這時候可以設置必須有值得屬性爲無主引用來解決循環強引用
cclass Person {
    let name: String
    init(name: String) {
        self.name = name
    }
    var apartment: Apartment?
    
    deinit {
        print("Person deinit")
    }
}

class Apartment {
    var unit: String
    unowned var person: Person
    
    init(unit: String, person: Person) {
        self.unit = unit
        self.person = person
    }
    
    deinit {
        print("Apartment deinit")
    }
}


var aPerson: Person? = Person(name: "小明")
var aApartment: Apartment? = Apartment(unit: "豪宅",person: aPerson!)
aPerson!.apartment = aApartment

aPerson = nil
aApartment = nil
  1. 無主引用和隱士解包可選值屬性
    如果兩個屬性都必須有值,這時候把其中一個設置爲無主引用,並正常完成構造器。
    把另一個屬性設置成隱士解包可選屬性,並將構造器傳入一個完成另一個對象初始化的字串參數(看情況)之後在利用另一個構造器完成初始化即可。
class Person {
    let name: String
    init(name: String, apartment: String) {
        self.name = name
        self.apartment = Apartment(unit: apartment, person: self)
    }
    
    
    var apartment: Apartment!
    
    deinit {
        print("Person deinit")
    }
}

class Apartment {
    var unit: String
    
    
    unowned var person: Person
    
    init(unit: String, person: Person) {
        self.unit = unit
        self.person = person
    }
    
    deinit {
        print("Apartment deinit")
    }
}

var aPerson: Person? = Person(name: "小明", apartment: "豪宅")
var aApartment: Apartment? = aPerson!.apartment

aPerson = nil
aApartment = nil
  1. 閉包內部使用方法,或者屬性,必須顯示的通過self調用。不能直接使用這些屬性和方法。
    這是因爲swift時刻提醒我們閉包內部有可能造成循環強引用。

  2. 用捕獲列表解決閉包的循環強引用

    1. swift中要求在閉包裏必須使用self顯示調用屬性和方法。
    2. 如果在閉包內發生了捕獲,那麼就要在閉包的參數列表和返回類型前面寫上捕獲列表來解決循環強引用。
    3. 如果這個閉包是不能設置成nil的那就要用無主引用。如果這個閉包可以設置成nil的,那就用弱引用。
class HTMLElement {
    var name: String
    var text: String?
    
    lazy var asHTML: () -> String = {
        [unowned self] in
        if let _ = self.text {
            return "<\(self.name)>\(self.text!)</\(self.name)>"
        }else{
            return "\(self.name)/"
        }
    }
    
    init(name: String, text: String) {
        self.name = name;
        self.text = text
    }

    deinit {
        print("HTMLElement deinit")
    }
}

var a: HTMLElement? = HTMLElement(name: "h1", text: "Hello World!")
print(a!.asHTML())
a = nil
  1. 總結
    1. 枚舉,結構體,字串等都是值類型。存儲在棧中,是編譯器進行內存管理,不用我們管理內存。
    2. 對象,引用類型是存在堆中。需要我們進行內存管理。ARC可以利用引用計數幫我們自動內存管理,但是有些情況下,如果我們不進行特殊處理會造成內存泄露。
    3. 兩個對象的屬性相互循環強引用
      1. 如果這兩個屬性都是可以設置成nil,那就把其中一個屬性用弱引用。
      2. 如果兩個屬性其中一個是可以設置成nil,另一個必須要有值。那麼就把必須有值的屬性用無主引用。
      3. 如果兩個屬性都是必須有值的,那麼就把其中一個屬性用無主引用類型,然後進行正常構造。另一個屬性用隱士解包可選類型,然後傳入一個參數字串(看情況用什麼類型),之後在這個構造器中調用另一個類的構造器進行構造。
    4. 閉包
      1. 閉包內swift要求必須通過顯示的self調用屬性和方法。(這樣可以時刻提醒我們循環強引用問題)
      2. 當發現閉包內部有導致發生循環強引用的對象時候,也就是發現有捕獲對象時候,我們要用捕獲列表解決循環強引用。
        1. 如果這個閉包有參數列表和返回值,那就在參數列表前邊寫捕獲列表。如果這個閉包能夠設置成nil,就用弱引用。如果不能就用無主引用。
        2. 如果閉包內部沒有參數列表和返回值,那就自己寫一個in,在in前邊寫捕獲列表。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章