스위프트 자동 참조 카운팅 (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 被析构