🔥 실전 ARC!

364자
5분

이번에는 ARC가 실제로 어떻게 동작하는지 살펴보도록 하겠습니다. 다음은 name이라는 상수 저장 속성을 가진 간단한 Person 클래스를 정의한 예시 코드예요.

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

Person 클래스는 인스턴스의 name 속성을 설정하고 초기화가 진행 중임을 나타내는 메시지를 출력하는 이니셜라이저를 가지고 있죠. 또한 클래스의 인스턴스가 할당 해제될 때 메시지를 출력하는 디이니셜라이저도 가지고 있습니다.

다음 코드 스니펫에서는 Person? 타입의 변수 세 개를 정의하고 있어요. 이 변수들은 이후 코드에서 새로운 Person 인스턴스에 대한 다중 참조를 설정하는 데 사용될 거예요. 이 변수들은 옵셔널 타입(Person?, Person이 아님)이기 때문에 자동으로 nil 값으로 초기화되며, 현재는 Person 인스턴스를 참조하지 않습니다.

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

이제 새로운 Person 인스턴스를 생성하여 이 세 변수 중 하나에 할당할 수 있겠죠.

reference1 = Person(name: "John Appleseed")
// "John Appleseed is being initialized" 출력
swift

Person 클래스의 이니셜라이저를 호출하는 시점에 "John Appleseed is being initialized" 메시지가 출력되는 것에 주목하세요. 이는 초기화가 이루어졌음을 확인시켜 줍니다.

새로운 Person 인스턴스가 reference1 변수에 할당되었기 때문에, 이제 reference1에서 새로운 Person 인스턴스로의 강한 참조가 생겼어요. 최소한 하나의 강한 참조가 있기 때문에 ARC는 이 Person이 메모리에 유지되고 할당 해제되지 않도록 합니다.

동일한 Person 인스턴스를 두 개의 다른 변수에 할당하면 해당 인스턴스에 대한 두 개의 강한 참조가 추가로 설정됩니다.

reference2 = reference1
reference3 = reference1
swift

이제 이 단일 Person 인스턴스에 대해 세 개의 강한 참조가 있게 되었네요.

두 개의 변수에 nil을 할당하여 이 강한 참조 중 두 개(원래 참조 포함)를 끊으면, 하나의 강한 참조만 남게 되고 Person 인스턴스는 할당 해제되지 않아요.

reference1 = nil
reference2 = nil
 
swift

ARC는 세 번째이자 마지막 강한 참조마저 끊어질 때까지 Person 인스턴스를 할당 해제하지 않습니다. 그 시점이 되어야 Person 인스턴스를 더 이상 사용하지 않는다는 것이 명확해지기 때문이죠.

reference3 = nil
// "John Appleseed is being deinitialized" 출력
swift

이렇게 ARC는 강한 참조의 수를 추적하여 인스턴스의 수명을 관리합니다. 강한 참조가 모두 사라지면 ARC는 해당 인스턴스가 더 이상 필요하지 않다고 판단하고 메모리에서 해제하는 거예요.

강한 참조의 수에 따른 인스턴스 해제 과정을 시각적으로 나타내면 다음과 같습니다:

lecture image

이처럼 ARC는 참조 횟수를 세어 메모리를 자동으로 관리해 줍니다. 개발자가 메모리 관리에 신경 쓰지 않아도 되는 편리한 방식이라고 할 수 있겠네요!