1. ARC(Automatic Reference Counting)
Swift에서 메모리 관리는 ARC을 통해 이루어진다.
객체가 생성될 때마다 강한 참조 카운터가 1씩 증가하고, 해당 객체를 참조하는 다른 객체가 생기면 카운트가 1씩 증가한다.
마찬가지로, 객체를 더 이상 참조하지 않으면 해당 객체에 대한 강한 참조 카운터는 1씩 감소하고 0이 되면 메모리에서 해제한다.
실제로 순환 참조가 생기는 상황을 만들어보자.
아래 코드 처럼 두 개 이상의 객체가 서로를 강하게 참조하면 순환 참조가 생기고 메모리 누수로 이어진다.

A Class에 B Class를 참조할때 weak 키워드를 붙여본다면, 순환 참조가 생기지 않고 메모리에서 해제되는 것을 볼 수 있다.

이처럼 weak 키워드를 붙여서 약한 참조를 하게 되면, ARC에서 B 객체의 강한 참조 횟수를 증가시키지 않는다.
위 코드에서 B는 "나를 참조하는 것은 strongCycle 하나네? strongCycle이 끝나면 소멸해야겠다." 라고 생각하기 때문에
strongCycle()이 끝나면 메모리에서 해제된다.
2. weak, unowned
강한 순환 참조를 방지하기 위해서는 weak 말고도 unowned(미소유 참조)가 있다.
둘 다 참조 카운트를 증가시키지 않기 때문에 강한 순환 참조를 예방할 수 있다.
차이점?
weak는 대상 객체가 메모리에서 해제되면 자동으로 nil로 설정되기 때문에 Optional 타입으로 선언되어야한다.
반면에 unowned는 항상 값이 있다고 가정하기 때문에
만약 메모리에서 해제가 되었는데 접근시 런타임 오류가 발생한다. 따라서 Optional 타입으로 선언되지 않는다.
(Swift 5.5부터는 Optional로 할 수 있다네요 ㅋ)
실제로 미소유 참조를 사용해서 Crash 되는 상황을 임의로 만들어보았다.
class A {
unowned var b: B
init(b: B) {
self.b = b
}
deinit {
print("A deinitialized")
}
func accessB() {
print("Accessing B: \(b)")
}
}
class B {
var a: A?
deinit {
print("B deinitialized")
}
}
B를 해제시키고 미소유 참조한 B에 접근해보면 아래와 같이 오류가 난다.

그럼 각각 언제쓸까?
위 코드에서 B의 생명주기가 끝났는데 A가 미소유 참조하고 있는 B를 접근하기 때문에 에러가 발생하는 것이다.
(A의 생명주기 >= B의 생명주기)
이러한 상황에서는 crash가 안나도록 weak를 써주고, 그 반대의 상황인 A의 생명주기 <= B의 생명주기 일때 unowned를 쓰는 것이 적절하다.
정리해보면,
참조 대상이 먼저 해제될 수 있으면 weak, 절대 먼저 해제되지 않는다면 unowned를 쓰자.
'iOS > Swift' 카테고리의 다른 글
| [Swift] 제네릭(Generic) (0) | 2025.07.12 |
|---|---|
| [Swift] 클로저, 클로저 캡쳐 (1) | 2025.07.08 |
| [SwiftUI] 렌더링 실험 (3) | 2025.06.25 |
| [Swift] @Published 뷰모델을 Combine Subject로 바꿔보자 (0) | 2025.06.23 |
| [Swift] SwiftData Concurrency 사용하기 (6) | 2025.06.20 |
댓글