관리 메뉴

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

[iOS - swift] (reference count) 참조 카운트의 정확한 이해 (weak var, retain cycle, ARC) 본문

iOS 기본 (swift)

[iOS - swift] (reference count) 참조 카운트의 정확한 이해 (weak var, retain cycle, ARC)

jake-kim 2021. 9. 8. 00:17

ARC의 기본 개념

참조 카운트 확인 방법

  • CGFGetRetainCount(object)를 사용하여 확인
// ex)

print(CFGetRetainCount(obejct1)) // 2
print(CFGetRetainCount(obejct1.property1)) // 2
print(CFGetRetainCount(obejct2)) // 2

obejct1.property1 = object2

print(CFGetRetainCount(obejct1)) // 2
print(CFGetRetainCount(obejct1.property1)) // 3
print(CFGetRetainCount(obejct2)) // 3

참조 카운트가 증가하는 구체적인 상황

  • 참초 가운트 테스트를 위한 클래스 정의
protocol AnimalDelegate {
    func update()
}

class Person {
    var name: String
    var animal: Animal

    init(name: String, animal: Animal) {
        self.name = name
        self.animal = animal
    }
}

extension Person: AnimalDelegate {
    func update() {
        print("update")
    }
}

class Animal {
    var delegate: AnimalDelegate?
    var name: String

    init(name: String) {
        self.name = name
    }
}
  • 카운트가 증가하는 경우
normalAnimal.delegate = normalPerson // normalPerson 값 +1
normalAnimal = normalPerson.animal // normalPerson은 변화 없지만, normalPerson.animal 값 +1
  • 주의
    • 1) 클래스에서 property를 접근할때, 해당 property도 참조당한 것이므로 +1
    • 2) 전체 객체가 오르지 않고 객체 내 다른 객체를 참조한 부분만 참조 카운트 +1
// normalPerson.animal 값 +1
// 1) normalAnimal 값 +1
// 2) normalPerson의 값은 유지

normalPerson.animal = normalAnimal
  • 카운트가 증가할것 같지만 증가하지 않는 경우
// 케이스1
/// normalAnimal 값 +1, normalPerson.animal 값 +1 (단, normalPerson이 아닌 animal값이 +1되는것을 주의)
normalPerson.animal = normalAnimal
/// normalPerson.animal의 값이 변하지 않고 유지되는 것을 주의 (위에서 이미 normalPerson에 의해 참조된 상태이므로)
normalAnimal = normalPerson.animal

//~~//

// 케이스2
/// normalPerson.animal의 값 +1 (normalAnimal이 참조해서 그런게 아닌, normalPerson이 참조하여 +1)
normalAnimal = normalPerson.animal
  • delegate를 weak var로 할 경우 참조 카운트 올라가지 않기때문에 retain cycle 방지
    • normalAnimal.delegate에서 delegate에 접근했으므로, `normalAnimal.delegate`의 값 +1
    • normalPerson은 delegate에게 참조를 당했지만 weak인 상태이므로 normalPerson의 값은 유지
    • weak delegate가 아닌 경우, Animal 클래스 내부의 프로퍼티와 normalPerson가 서로 참조하는 상황 (retain cycle)
class Animal {
    weak var delegate: AnimalDelegate?
    ...
}

normalAnimal.delegate = normalPerson // normalPerson 값 유지
  • 전체 코드
protocol AnimalDelegate: AnyObject {
    func update()
}

class Person {
    var name: String
    var animal: Animal

    init(name: String, animal: Animal) {
        self.name = name
        self.animal = animal
    }
}

extension Person: AnimalDelegate {
    func update() {
        print("update")
    }
}

class Animal {
    var delegate: AnimalDelegate?
    var name: String

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

var normalPerson = Person(name: "jake", animal: Animal(name: "jake-"))
var normalAnimal = Animal(name: "강아지")

print(CFGetRetainCount(normalPerson))
normalPerson.animal = normalAnimal // normalAnimal 값 +1
print(CFGetRetainCount(normalPerson))

print(CFGetRetainCount(normalPerson.animal))
normalAnimal = normalPerson.animal // normalPerson은 변화 없지만, normalPerson.animal 값 +1
print(CFGetRetainCount(normalPerson.animal))
Comments