Latest web development tutorials

Swift Автоматический подсчет ссылок (ARC)

Swift Use Automatic Reference Counting (ARC) этот механизм для отслеживания и управления памятью приложений

При нормальных обстоятельствах, нам не нужно вручную освободить память, потому что ARC будет экземпляром класса больше не используется, автоматически освободить память.

Но нам еще нужно реализовать код управления памятью в некоторых случаях.

функция ARC

  • При инициализации () Создает новый экземпляр класса каждого метода, когда АРК выделит блок памяти для хранения информации экземпляра.

  • Тип информации, содержащейся в памяти, будут иметь место случаи, а также значение этого экземпляра все соответствующие атрибуты.

  • Когда экземпляр больше не используется, ARC не освобождает память, занятую экземпляром, и пусть освобождается память может использоваться для других целей.

  • Для того, чтобы гарантировать, что экземпляр не будет уничтожен, ARC будет отслеживать и вычислять каждый экземпляр на который ссылается на количество атрибутов, констант и переменных.

  • Примеры, присвоенное свойству, постоянной или переменной, они создадут сильную ссылку данного экземпляра, пока ссылка все еще сильна, экземпляр не может быть уничтожен.

примеры 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

Выход выше выполнение программы:

w3big 开始初始化
w3big 被析构

Примеры сильной циркуляции между ссылками класса

В приведенном выше примере, ARC будет отслеживать вновь созданный Person ссылочный количество экземпляров, и он не будет уничтожен, когда экземпляр Person больше не нужен.

Тем не менее, мы могли бы написать код, подобный этому, никогда не будет одного класса 0 сильные ссылки. Это происходит в двух экземпляров классов, чтобы поддерживать сильные ссылки друг на друга, и пусть другая сторона не будет уничтожена. Это так называемые сильные циклические ссылки.

примеров

Следующий пример показывает цикл непреднамеренно производят сильные ссылки. Пример определяет два класса: Человек и квартира, используемые для моделирования квартиры и его жители:

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

Примеры сильного решения циркулирует между заданием

Swift обеспечивает два способа решить эту петлю вы используете атрибут класса, когда встречаются сильные опорные вопросы:

  • Слабые ссылки
  • Нет первичных документов

Слабые ссылки и не основные ссылки позволяют циклическую ссылку в экземпляре ссылки на другой экземпляр без сохранения сильной ссылки. Такие случаи могут ссылаться друг на друга, не создавая сильного опорного цикла.

Для жизненного цикла становится нулевым экземпляр использует слабые ссылки. В отличие от этого, после того, как значения инициализации не будет присвоен ноль, например, использование неосновной ссылки.

Примеры слабых ссылок

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

Выход выше выполнение программы:

ARC 主模块
子模块 topic 数为 4

Нет основные ссылки на примеры

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

Выход выше выполнение программы:

ARC
学生的分数为 98

замыкания петли, вызванные сильными ссылками

Сильный опорный цикл происходит также при назначении закрытия экземпляра класса собственности, а тело закрытия и использование примеров. Тело крышка может получить доступ к свойству экземпляры, такие как self.someProperty или замыкание методов экземпляра вызова, такие self.someMethod. Оба случая привели к закрытию "захвата" я, в результате чего в цикле сильных ссылок.

примеров

Как после того, как Следующий пример показывает вам, когда замыкание является получение ссылки на само цикла сильных ссылок. Пример определяет класс под названием HTMLElement, выраженное в простой модели одного 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())

Класс HTMLElement произвел экземпляры классов цикла и закрытия asHTML значения по умолчанию между сильными ссылками.

Сильно asHTML экземпляр свойство содержит ссылку на замыкание. Тем не менее, закрытие его закрытия в естественных условиях использования собственного (цит self.name и self.text), и, следовательно, сам захват замыкание, что означает закрытие, в свою очередь, имеет сильную ссылку HTMLElement экземпляра. Так что два объекта производит круглую сильную ссылку.

замыкание петли, вызванное сильным Resolve Цитата: При определении окончания в то же время, как часть определения закрытия списка улов таким образом могут быть решены между закрытием петель и сильной ссылкой на экземпляр класса.


Слабые ссылки и ссылки на бесхозяйные

Когда экземпляр закрытий и захватили всегда относятся друг к другу и всегда в то же время разрушен, захваченных в определение закрытия не главным ориентиром.

И наоборот, когда ссылки захвата может иногда быть нулем, то замыкание будет захвачено в пределах определения слабых ссылок.

Если вы захватить ссылка не будет установлен в ноль, это не должно быть главным ориентиром, а не слабых ссылок.

примеров

HTMLElement выше примере, главным ориентиром не правильный путь для решения круговой сильной ссылки. Такой класс записи HTMLElement, чтобы избежать круговой сильной ссылки:

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

Выход выше выполнение программы:

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