Swift编程中用以管理内存的自动引用计数详解

Swift 内存管理功能是通过使用自动引用计数(ARC)来处理。ARC用于初始化和取消初始化所述系统资源,从而释放使用的类实例的存储器空间当实例不再需要。ARC跟踪代码的实例有效地管理存储资源之间的关系的信息。

ARC的功能

  • 在每一次一个新的类实例被创建时ARC分配一块内存以存储信息 init()
  • 关于实例类型和其值的信息存储在存储器中
  • 当类实例不再需要它自动由 deinit() 释放,用于进一步类实例的存储和检索的存储空间
  • ARC保存在磁道当前参照类实例的属性,常量和变量,使得 deinit() 仅适用于那些不使用的实例。
  • ARC维护“强引用”这些类实例属性,常量和变量来限制释放当当前的类实例正在使用。

ARC 程序


class StudDetails {

    var stname: String!

    var mark: Int!

    init(stname: String, mark: Int) {

        self.stname = stname

        self.mark = mark

    }

    

    deinit {

        println("Deinitialized \(self.stname)")

        println("Deinitialized \(self.mark)")

    }

}

let stname = "swift" let mark = 98

println(stname) println(mark)


当我们使用 playground 运行上面的程序,得到以下结果。

swift
98

ARC 强参考周期类实例


class studmarks {

    let name: String

    var stud: student?

    

    init (name: String) {

        println("Initializing: \(name)")

        self.name = name

    }

    

    deinit {

        println("Deallocating: \(self.name)")

    }

}

class student {     let name: String     var strname: studmarks?         init (name: String) {         println("Initializing: \(name)")         self.name = name     }         deinit {         println("Deallocating: \(self.name)")     } }

var shiba: studmarks? var mari: student?

shiba = studmarks(name: "Swift") mari = student(name: "ARC")

shiba!.stud = mari mari!.strname = shiba


当我们使用 playground 运行上面的程序,得到以下结果。

Initializing: Swift
Initializing: ARC

ARC弱和无主参考
Class类型属性有两种方法可以解决强引用周期:

  1. 弱引用
  2. 无主参考

这些引用是用来使一个实例指在一个基准周期其他实例。然后实例可以为每一个实例参考代替处理强引用周期。当用户知道某些情况下可能会返回 'nil' 值,我们可能会指向使用弱引用。当实例会返回不是零的东西,然后使用无主参考声明。

弱引用程序


class module {

    let name: String

    init(name: String) { self.name = name }

    var sub: submodule?

    deinit { println("\(name) Is The Main Module") }

}

class submodule {     let number: Int         init(number: Int) { self.number = number }         weak var topic: module?         deinit { println("Sub Module with its topic number is \(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


当我们使用 playground 运行上面的程序,得到以下结果。

ARC Is The Main Module
Sub Module with its topic number is 4

无主参考程序


class student {

    let name: String

    var section: marks?

    

    init(name: String) {

        self.name = name

    }

    

    deinit { println("\(name)") }

}

class marks {

    let marks: Int

    unowned let stname: student

    

    init(marks: Int, stname: student) {

        self.marks = marks

        self.stname = stname

    }

    

    deinit { println("Marks Obtained by the student is \(marks)") }

}

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


当我们使用 playground 运行上面的程序,得到以下结果。

ARC
Marks Obtained by the student is 98

闭包强引用周期
当我们分配一个闭包至类实例属性,闭包的主体以捕获特定实例强参考周期发生。强引用闭合由 self.someProperty 或 self.someMethod()定义。强引用周期用作闭包引用类型。


class HTMLElement {

    let samplename: String

    let text: String?

    

    lazy var asHTML: () -> String = {

        if let text = self.text {

            return "<\(self.samplename)>\(text)</\(self.samplename)>"

        } else {

            return "<\(self.samplename) />"

        }

    }

    

    init(samplename: String, text: String? = nil) {

        self.samplename = samplename

        self.text = text

    }

    

    deinit {

        println("\(samplename) is being deinitialized")

    }

}

var paragraph: HTMLElement? = HTMLElement(samplename: "p", text: "Welcome to Closure SRC") println(paragraph!.asHTML())


当我们使用 playground 运行上面的程序,得到以下结果。

<p>Welcome to Closure SRC</p>
弱和无主参考
当闭包和实例相互引用,用户可以定义在一个闭合作为无主引用捕获。它不会允许用户在同一时间解除分配实例。当实例在某个时候返回一个“nil” 定义并使用弱实例的值。


 class HTMLElement {

    let module: String

    let text: String?

    

    lazy var asHTML: () -> String = {

        [unowned self] in

        if let text = self.text {

            return "<\(self.module)>\(text)</\(self.module)>"

        } else {

            return "<\(self.module) />"

        }

    }

    

    init(module: String, text: String? = nil) {

        self.module = module

        self.text = text

    }

    

    deinit {

        println("\(module) the deinit()")

    }

}

var paragraph: HTMLElement? = HTMLElement(module: "Inside", text: "ARC Weak References") println(paragraph!.asHTML()) paragraph = nil


当我们使用 playground 运行上面的程序,得到以下结果。

<Inside>ARC Weak References</Inside>
Inside the deinit()