
TIL 15일 차 - Swift 문법 ARC 순환참조 해제 문제
- 클래스 A, B 사이에 순환참조가 발생하도록 구현해 주세요.
- 각 클래스에 deinit 을 정의하여, 메모리 해제 여부를 확인할 수 있도록 해주세요.
먼저 서로가 서로를 강하게 붙잡고 있어(Strong Reference), 아무도 메모리에서 사라지지 못하는 상황을 만들어야 한다.
1. 클래스 간 순환: ClassA는 ClassB를 가지고, ClassB는 ClassA를 가진다.
// 1. 클래스 정의
class A {
var b: B? // A가 B를 참조함 (기본값은 Strong)
deinit {
print("A 메모리 해제 됨 (Deinit)")
}
}
class B {
var a: A? // B가 A를 참조함 (서로가 서로를 참조 중 -> 순환 참조 1)
deinit {
print("B 메모리 해제 됨 (Deinit)")
}
}
var a: A? = A()
var b: B? = B()
a?.b = b
b?.a = a
a = nil // nil 값을 대입해서 메모리 해제를 시험함
b = nil // 이러한 이유로 앞에서 옵셔널로 선언
// 아무것도 출력되지 않음
// 서로가 서로를 인질로 잡아 deinit이 호출되지 않음
A ──strong──▶ B
B ──strong──▶ A
weak 참조 특징
- 참조는 하지만 소유하지 않음
- 그래서 상대가 사라지면 -> 자동으로 nil
- 따라서 옵셔널 이어야 함
import UIKit
// 해결 방법: 둘 중에 하나가 약하게 잡으면 됨
class A {
var b: B? // A가 B를 참조함 (기본값은 Strong)
deinit {
print("A 메모리 해제 됨 (Deinit)")
}
}
class B {
weak var a: A? // B가 A를 약하게 참조함 🛠️
deinit {
print("B 메모리 해제 됨 (Deinit)")
}
}
var a: A? = A()
var b: B? = B()
a?.b = b
b?.a = a
a = nil
b = nil
// A 메모리 해제 됨 (Deinit)
// B 메모리 해제 됨 (Deinit)
2. 클로저 순환: ClassB의 클로저가 ClassA를 사용하며 또 한 번 강하게 붙잡음
- 또한 클래스 B 에는 closure: (() -> Void)? 프로퍼티를 만들고, 클로저 내부에서 A의 인스턴스를 참조하게 하여 클로저 기반의 순환 참조도 발생시켜 보세요.
이 케이스는 실무에서도 제일 많이 터지는 경우 중 하나라고 한다.
class A {
deinit {
print("A 메모리 해제 됨 (Deinit)")
}
}
class B {
var a: A?
var closure: (() -> Void)?
deinit {
print("B 메모리 해제 됨 (Deinit)")
}
}
var a: A? = A()
var b: B? = B()
b?.a = a // 이 케이스는 순환참조가 아님
b?.closure = {
print(a!) // A를 강하게 캡쳐
}
a = nil
b = nil
이게 순환 참조인 이유는
B ──strong──▶ closure
closure ──strong──▶ A
클로저는 기본적으로 strong capture임
그래서 A를 놓지 않아 deinit 불가
- 순환 참조를 해결할 수 있도록 weak, unowned 키워드를 클로저 캡처 리스트를 적절히 사용하여 순환 참조를 해결해 주세요.
b?.closure = { [weak a] in // 이 클로저 안에서는 a를 약하게 잡겠다는 뜻
guard let a else { return }
print(a) // A를 weak 캡쳐
}
// 순환참조 문제 해결
그렇다면 이렇게 비슷해 보이는 weak과 unowned의 차이점은 무엇이냐
| weak | unowned |
| 옵셔널 | 옵셔널 X |
| 안전 | 위험 (이미 해제되면 크래시) |
| 언제나 사용 가능 | 절대 먼저 안 죽는 게 보장될 때만 |
| 성능 느림 | 성능 빠름 |
일단 초보자 단계에서는 weak만 써도 충분하다고 기억해 주면 편하다.
해결 방법 정리
- 참조 중 하나를 weak / unowned
- 클로저 캡처 리스트에 weak / unowned
'iOS > Swift ' 카테고리의 다른 글
| [iOS-Swift] 기초 문법 개인 과제 최최최종_리팩토링.swift (0) | 2026.01.14 |
|---|---|
| [iOS-Swift] 에러처리 (0) | 2026.01.14 |
| [iOS-Swift] 객체 지향 프로그래밍 OOP (0) | 2026.01.14 |
| [iOS-Swift] 스위프트에서 사용자 입력받기 (0) | 2026.01.13 |
| [iOS-Swift] 문법 기초주차 과제 최종 리펙토링 (0) | 2026.01.12 |