Swift의 strong, weak, unowned 참조
ARC에서 strong, weak, unowned 참조가 객체의 생명주기에 미치는 영향과 선택 기준을 비교합니다.

두 객체가 서로를 오래 붙잡고 있으면 화면에서는 사라졌는데 메모리에서는 남아 있는 일이 생긴다. ARC가 참조를 세는 방식과 strong, weak, unowned가 그 관계를 어떻게 바꾸는지 함께 정리했다.
순환 참조
A가 B를 참조하고 B가 A를 참조하는 경우 같이 두 객체가 서로를 참조하면 순환 참조가 발생한다. 순환 참조가 발생하면 ARC의 Reference Count가 절대 0이 되지 않아 메모리에서 해제되지 않고 메모리 누수(Memory Leak)가 발생한다.
class ClassA {
var instanceB: ClassB?
deinit {
print("ClassA Deinitialized")
}
}
class ClassB {
var instanceA: ClassA?
deinit {
print("ClassB Deinitialized")
}
}
var instanceA: ClassA? = ClassA()
var instanceB: ClassB? = ClassB()
// 서로의 인스턴스 참조
instanceA?.instanceB = instanceB
instanceB?.instanceA = instanceA
// nil이 되었지만 참조가 해제되지 않아 순환 참조 발생
instanceA = nil
instanceB = nil
Strong(강한 참조)
기본적인 참조 유형으로 별도의 지정자를 사용하지 않으면 strong 참조이다. Reference Count를 1 증가시켜, 객체를 참조하고 있으면 해당 객체는 메모리에서 해제되지 않는다.
class Person {
var pet: Pet?
}
class Pet {
var owner: Person?
}
let snack = Person()
let cream = Pet()
snack.pet = cream
cream.owner = snack
// 순환 참조가 발생하여 snack과 cream 객체는 메모리에서 해제되지 않는다.

Weak(약한 참조)
객체의 Reference Count를 증가시키지 않는다. weak 참조를 통해 참조되는 객체가 없어지면 자동으로 nil이 되기 때문에, weak 참조는 항상 옵셔널 타입이어야 한다.
class Person {
var pet: Pet?
}
class Pet {
weak var owner: Person?
}
let snack = Person()
let cream = Pet()
snack.pet = cream
cream.owner = snack
// cream 객체가 메모리에서 해제되면 cream.owner는 자동으로 nil이 된다.

Unowned(미소유 참조)
객체의 Reference Count를 증가시키지 않는다. unowned 참조는 참조하는 대상이 항상 메모리에 존재할 것이라는 확신이 있을 때 사용하기 때문에 옵셔널 타입이 될 수 없다. 참조되는 객체가 메모리에서 해제되어도 해당 참조를 계속 하려하기 때문에 런타임 오류가 발생한다.
class Person {
var pet: Pet?
}
class Pet {
unowned var owner: Person
init(owner: Person) {
self.owner = owner
}
}
let snack = Person()
let cream = Pet(owner: snack)
snack.pet = cream
// snack 객체가 메모리에서 해제되고 이후에 cream.owner에 접근하려고 시도하면 런타임 오류가 발생한다.
