Latest web development tutorials

Swift Automatic Reference Counting (ARC)

Swift Automatic Reference Counting Zastosowanie (ARC) to mechanizm śledzenia i zarządzania pamięci aplikacji

W normalnych warunkach, nie trzeba ręcznie zwolnić pamięć, ponieważ ARC będzie instancją klasy nie jest już używany, automatycznie zwolnić pamięć.

Ale wciąż musimy zaimplementować kod zarządzania pamięcią w niektórych przypadkach.

funkcja ARC

  • Gdy init () Tworzy nową instancję klasy każdej metody, kiedy ARC przeznaczy kawał pamięci do przechowywania instancji informacyjnego.

  • Rodzaj informacji zawartych w pamięci zostaną przypadki, jak również wartość tym przypadku wszystkie odpowiednie atrybuty.

  • Gdy przykład nie jest już używany, ARC zwolnienia pamięci zajmowanych przez przykład, niech uwolniony pamięci może być używany do innych celów.

  • Aby upewnić się, że instancja nie zostaną zniszczone, ARC będzie śledzić i obliczyć każde wystąpienie jest określany przez liczbę cech, stałych i zmiennych.

  • Przykłady przypisana do właściwości, stała lub zmienna, będą tworzyć wyraźne odniesienie to wystąpienie, o ile mowa jest nadal silna, instancja nie może być zniszczona.

przykłady ARC

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) 开始初始化")
    }
    deinit {
        print("\(name) 被析构")
    }
}

// 值会被自动初始化为nil,目前还不会引用到Person类的实例
var reference1: Person?
var reference2: Person?
var reference3: Person?

// 创建Person类的新实例
reference1 = Person(name: "w3big")


//赋值给其他两个变量,该实例又会多出两个强引用
reference2 = reference1
reference3 = reference1

//断开第一个强引用
reference1 = nil
//断开第二个强引用
reference2 = nil
//断开第三个强引用,并调用析构函数
reference3 = nil

Wyjście powyżej wykonywanie programu jest:

w3big 开始初始化
w3big 被析构

Przykłady silnej cyrkulacji pomiędzy odniesień klasowych

W powyższym przykładzie, ARC będzie śledzić swoje nowo utworzony numer referencyjny osobie przypadkach, a zostanie ona zniszczona, gdy instancja Osoba nie jest już potrzebna.

Jednakże, możemy napisać kod tak, że nigdy nie będzie klasa 0 silne referencje. Dzieje się tak w dwóch przypadkach klasy do utrzymania silnych odwołań do siebie i niech druga strona nie zostaną zniszczone. Jest to tak zwane silnymi odniesienia kołowy.

Przykłady

Poniższy przykład pokazuje pętlę przypadkowo wytwarzają silne referencje. Przykład definiuje dwie klasy: Osoba i apartament, używane do modelowania mieszkanie i jego mieszkańcy byli:

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) 被析构") }
}

class Apartment {
    let number: Int
    init(number: Int) { self.number = number }
    var tenant: Person?
    deinit { print("Apartment #\(number) 被析构") }
}

// 两个变量都被初始化为nil
var w3big: Person?
var number73: Apartment?

// 赋值
w3big = Person(name: "w3big")
number73 = Apartment(number: 73)

// 意感叹号是用来展开和访问可选变量 w3big 和 number73 中的实例
// 循环强引用被创建
w3big!.apartment = number73
number73!.tenant = w3big

// 断开 w3big 和 number73 变量所持有的强引用时,引用计数并不会降为 0,实例也不会被 ARC 销毁
// 注意,当你把这两个变量设为nil时,没有任何一个析构函数被调用。
// 强引用循环阻止了Person和Apartment类实例的销毁,并在你的应用程序中造成了内存泄漏
w3big = nil
number73 = nil

Przykłady stężony roztwór przepływa pomiędzy wartością zadaną

Swift oferuje dwa sposoby na rozwiązanie pętli użyć atrybutu class, gdy napotkał silne pytania referencyjnych:

  • słabe referencje
  • Brak odniesienia pierwotne

Słabe referencje i żadnych odniesień główne umożliwiają odwołanie cykliczne w wystąpieniu odniesienia do innej instancji bez zachowania silnego odniesienia. Takie przypadki mogą odnosić się do siebie, nie generując silny cykl odniesienia.

Przez cały cykl życia staje się zerowa instancji wykorzystuje słabe referencje. W przeciwieństwie do tego, po tym, jak wartości inicjalizacji nie zostanie przypisany do zera przykład, stosowanie nie pierwotnej odniesienia.

Przykłady słabych referencji

class Module {
    let name: String
    init(name: String) { self.name = name }
    var sub: SubModule?
    deinit { print("\(name) 主模块") }
}

class SubModule {
    let number: Int
    
    init(number: Int) { self.number = number }
    
    weak var topic: Module?
    
    deinit { print("子模块 topic 数为 \(number)") }
}

var toc: Module?
var list: SubModule?
toc = Module(name: "ARC")
list = SubModule(number: 4)
toc!.sub = list
list!.topic = toc

toc = nil
list = nil

Wyjście powyżej wykonywanie programu jest:

ARC 主模块
子模块 topic 数为 4

Brak główne przykłady referencyjne

class Student {
    let name: String
    var section: Marks?
    
    init(name: String) {
        self.name = name
    }
    
    deinit { print("\(name)") }
}
class Marks {
    let marks: Int
    unowned let stname: Student
    
    init(marks: Int, stname: Student) {
        self.marks = marks
        self.stname = stname
    }
    
    deinit { print("学生的分数为 \(marks)") }
}

var module: Student?
module = Student(name: "ARC")
module!.section = Marks(marks: 98, stname: module!)
module = nil

Wyjście powyżej wykonywanie programu jest:

ARC
学生的分数为 98

zamknięcia pętli spowodowane silnymi odniesieniami

Silne cyklu odniesienia występuje również podczas przypisywania zamknięcie instancji klasy nieruchomości, a ciało zamknięcia i wykorzystanie przykładów. Korpus zamknięcia może uzyskiwać dostęp do wystąpień własności, takie jak self.someProperty lub zamknięcie rozmowy metod przykład takiego self.someMethod. W obu przypadkach doprowadzić do zamknięcia "przechwytywania" sobą, powodując w cyklu silnych odniesienia.

Przykłady

Jak po Poniższy przykład pokazuje wam, gdy zamknięcie jest wytworzenie odniesienie do pętli siebie silnymi odniesieniami. Przykład definiuje klasę o nazwie HTMLElement, wyrażony w prostym modelu pojedynczego elementu HTML:

class HTMLElement {
    
    let name: String
    let text: String?
    
    lazy var asHTML: () -> String = {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }
    
    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        print("\(name) is being deinitialized")
    }
    
}

// 创建实例并打印信息
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())

Klasa HTMLElement produkowane klasę instancji i zamknięcia cyklu asHTML wartości domyślnych między silnymi odniesieniami.

Silne asHTML instancji Obiekt posiada odniesienie do zamknięcia. Jednak zamknięcie jego zamknięciu stosowania in vivo siebie (cytowane self.name i self.text) i dlatego jaźni przechwytywania zamknięcia, co oznacza zamknięcie w kolei, posiada wyraźne odniesienie HTMLElement instancji. Tak, że dwa obiekty produkuje okrągły silne odniesienie.

Zamknięcie pętli spowodowane silnym resolve Cytat: Podczas definiowania zamknięcia w tym samym czasie jako część definicji zamknięcia listy połowu w ten sposób można rozwiązać między zamknięciem pętli i silnym odniesieniem do instancji klasy.


Słabe referencje i referencje niczyj

Instancja zamknięcia i wychwytywano odnoszą się zawsze do siebie i są zawsze w tym samym czasie, zniszczone, ujęte w ramach definicji zamknięcia ma główne odniesienie.

Z drugiej strony, gdy odniesienia wychwytywania może czasami być równa zeru, to zamknięcie zostanie zatrzymany w definicji słabych odniesienia.

Jeśli uchwycić odwołanie nie zostanie ustawiony na zero, nie powinno być głównym punktem odniesienia, a nie słabych referencji.

Przykłady

HTMLElement powyższym przykładzie, głównym punktem odniesienia nie jest właściwym sposobem rozwiązywania okrągły silne odniesienie. Taka klasa zapisu HTMLElement uniknąć okrągły wyraźne odniesienie:

class HTMLElement {
    
    let name: String
    let text: String?
    
    lazy var asHTML: () -> String = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }
    
    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    
    deinit {
        print("\(name) 被析构")
    }
    
}

//创建并打印HTMLElement实例
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())

// HTMLElement实例将会被销毁,并能看到它的析构函数打印出的消息
paragraph = nil

Wyjście powyżej wykonywanie programu jest:

<p>hello, world</p>
p 被析构