Latest web development tutorials

Swift Automatic Reference Counting (ARC)

Swift Use Automatic Reference Counting (ARC) this mechanism to track and manage application memory

Under normal circumstances, we do not need to manually release the memory, because the ARC will be an instance of the class is no longer used, automatically free up memory.

But we still need to implement memory management code in some cases.

ARC function

  • When init () Creates a new instance of a class of each method when, ARC will allocate a chunk of memory for storing information instance.

  • The type of information contained in memory will be instances, as well as the value of this instance all the relevant attributes.

  • When the instance is no longer being used, ARC release the memory occupied by the instance, and let the freed memory can be used for other purposes.

  • To ensure that the instance will not be destroyed, ARC will track and calculate each instance is being referenced by the number of attributes, constants and variables.

  • Examples assigned to the property, constant or variable, they will create a strong reference this instance, as long as the reference is still strong, the instance is not allowed to be destroyed.

ARC examples

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

The above program execution output is:

w3big 开始初始化
w3big 被析构

Examples of strong circulation between class references

In the above example, ARC will track your newly created Person reference number of instances, and it will be destroyed when the Person instance is no longer needed.

However, we might write code like this, there will never be a class 0 strong references. This occurs in two class instances to maintain strong references to each other, and let the other party will not be destroyed. This is the so-called strong circular references.

Examples

The following example shows a loop inadvertently produce strong references. Example defines two classes: Person and Apartment, used to model apartment and its inhabitants were:

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

Examples of strong solution circulates between the reference

Swift provides two ways to solve the loop you use the class attribute when encountered strong reference questions:

  • Weak references
  • No primary references

Weak references and no main references allow a circular reference in an instance of a reference to another instance without maintaining a strong reference. Such instances can refer to each other without generating a strong reference cycle.

For the life cycle becomes nil instance uses weak references. In contrast, after the initialization values ​​will not be assigned to nil instance, the use of non-primary reference.

Examples of weak references

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

The above program execution output is:

ARC 主模块
子模块 topic 数为 4

No main reference examples

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

The above program execution output is:

ARC
学生的分数为 98

Loop closures caused by strong references

Strong reference cycle also occurs when you assign a class instance closure of a property, and the closure body and the use of examples. The closure body may access a property instances, such as self.someProperty, or the closure of a call instance methods, such self.someMethod. Both cases have led to closure "capture" self, resulting in a cycle of strong references.

Examples

How after following example shows you when a closure is to produce a reference to the self loop strong references. Example defines a class called HTMLElement, expressed in a simple model of a single HTML element:

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 class produced a cycle class instances and closures asHTML default values ​​between strong references.

Strong asHTML property instance holds a reference to the closure. However, the closure of its closure in vivo use of self (cited self.name and self.text), and therefore the closure capture self, which means the closure, in turn, holds a strong reference HTMLElement instance. So that the two objects produces circular strong reference.

Loop closure caused by the strong resolve Quote: When you define a closure at the same time as part of the definition of the catch list closure in this way can be resolved between the loop closures and a strong reference to the class instance.


Weak references and references ownerless

When an instance of closures and captured always refer to each other and are always at the same time destroyed, captured within the definition of closure is no main reference.

Conversely, when the capture references may sometimes be nil, the closure will be captured within the definition of weak references.

If you capture a reference will not be set to nil, it should be no main reference instead of weak references.

Examples

HTMLElement foregoing example, the main reference is no right way to resolve circular strong reference. Such write HTMLElement class to avoid circular strong reference:

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

The above program execution output is:

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