Latest web development tutorials

스위프트 자동 참조 카운팅 (ARC)

스위프트를 사용하여 자동 참조 카운팅 (ARC)이 메커니즘을 추적하고 응용 프로그램 메모리를 관리하는

정상적인 상황에서, 우리는 수동으로 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는 인스턴스의 새로 만든 사람이 참조 번호를 추적 할 것이며, 인 인스턴스가 더 이상 필요 때 파괴되지 않는다.

그러나 우리는이 같은 코드를 작성할 수 있습니다, 클래스 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

강한 용액의 예로는 상기 기준 사이 순환

스위프트는 강한 참조 문제가 발생했을 때 클래스 속성을 사용하여 루프를 해결하는 두 가지 방법을 제공합니다 :

  • 약한 참조
  • 없음 기본 참조 없음

약한 참조없이 주요 참조 강한 참조를 유지하지 않고 다른 인스턴스에 대한 참조의 인스턴스에서 순환 참조 할 수 있습니다. 이러한 경우는 강한 참조주기를 생성하지 않고 서로에 대해 참조 할 수있다.

수명주기 위해 전무 인스턴스가 약한 참조를 사용하게된다. 한편, 초기 값은 전무 인스턴스에 할당되지 후 비 기본 참조 용도.

약한 참조의 예

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의 폐쇄에 액세스 할 수 있습니다. 두 경우 모두 강한 참조주기의 결과로 폐쇄 "캡처"자기 주도했다.

어떻게 폐쇄가 자기 루프 강한 참조에 대한 참조를 생성하는 경우 예를 들어 다음을을 보여줍니다 후. 예는 단일 HTML 요소의 간단한 모델에서 발현는 HTMLElement라는 클래스를 정의한다 :

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 인스턴스를 보유하고있다. 두 객체가 원형 강한 참조를 생산하고 그래서.

강한 해결 견적 의한 루프 폐쇄 :이 방법 캐치리스트 종결 정의의 일부로서 동시에 폐쇄를 정의 할 때 루프 폐쇄 및 클래스 인스턴스에 대한 강한 참조 사이 해결 될 수있다.


약한 참조와 임자 참조

폐쇄의 인스턴스와 항상 촬영이 파괴 동시에 항상 서로를 참조하고있는 경우 폐쇄의 정의가 더 주요 기준입니다 내에서 촬영.

캡처 참조 때로는 전무있을 수 있습니다 때 반대로, 폐쇄는 약한 참조의 정의에 캡처됩니다.

당신이 참조가 전무로 설정되지 않습니다 캡처 경우, 대신 약한 참조에는 주요 참조 할 수 없습니다.

예를 전술 한는 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 被析构