관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift 공식 문서] 24. ARC (Auto Reference Counting) 본문

swift 공식 문서

[iOS - swift 공식 문서] 24. ARC (Auto Reference Counting)

jake-kim 2021. 7. 24. 20:59

ARC

  • 앱의 메모리 사용량을 추적하고 관리하는 방법
  • 인스턴스가 생성될 때마다 ARC는 해당 인스턴스에 대한 정보를 저장하기 우해 메모리 청크를 할당
  • ARC는 strong reference를 통해, 현재 사용중인 instance가 메모리 해제되지 않도록 유지
  • ARC는 현재 인스턴스를 참조하는 속성, 상수, 변수의 count를 추적 > count가 하나 이상 존재하는 한 인스턴스를 할당해제하지 않는 것

ex)

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    deinit {
        print("\(name) is being deinitialized")
    }
}

var reference1: Person?
var reference2: Person?
var reference3: Person?

reference1 = Person(name: "John Appleseed")
// Prints "John Appleseed is being initialized"

reference2 = reference1
reference3 = reference1

reference1 = nil
reference2 = nil
reference3 = nil // reference1 해제: Prints "John Appleseed is being deinitialized"

Reference Strong Cycle

  • cycle이 발생하는 사례
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil
unit4A = nil
// 해제되지 않는 상태

  • instance안에 property가 서로를 참조하고 있어서 count가 각각 +1인 상태

Weak 키워드를 통해 Strong Reference Cycle 해결

  • weak 키워드의 property: 해당 property로 다른 instance를 참조하면 그 instance의 참조 count는 늘어나지 않는 상태
class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var john: Person?
var unit4A: Apartment?

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil
// Prints "John Appleseed is being deinitialized"

  • strong 변수들의 참조 관계에서 cycle이 생기지 않도록 주의

Capture List

  • Closure도 하나의 instance로 생각할 수 있고, 이 closure에서 자기 자신을 strong하게 참조하면, cycle이 생기는것 주의
let heading = HTMLElement(name: "h1")
let defaultText = "some default text"
heading.asHTML = {
    return "<\(heading.name)>\(heading.text ?? defaultText)</\(heading.name)>"
}

  • [weak self]나 [unownd self] 사용하여 해결
    lazy var asHTML: () -> String = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

* 참고

https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html

Comments