Notice
Recent Posts
Recent Comments
Link
大器晩成
강함참조 사이클(Strong Reference Cycles Between Class Instances) 본문
iOS/Swift 문법
강함참조 사이클(Strong Reference Cycles Between Class Instances)
zerobugpark 2025. 3. 3. 15:56두 클래스 인스턴스가 서로에 대한 강한 참조를 유지하여 각 인스턴스가 다른 인스턴스를 유지하는 경우 강한 참조사이클이라고 합니다. 이때, 메모리 누수가 발생됩니다.
Apple 공식문서 예제
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
- john은 Person 인스턴스에 대한 강한 참조 사이클을 가지고 있으며, unit4A도 Apartment에 대한 강함 참조 사이클을 가지고 있습니다.
john!.apartment = unit4A
unit4A!.tenant = john
- john인스턴스 내의 apatment는 unit4A를 참조하게 되면 Person 인스턴스는 Apartment에 대한 강한 참조 사이클이 발생합니다.
- tenant는 Person에 대한 인스턴스를 참조하고 있으며, 이대 Apartment 인스턴스는 Person에 대한 강한 참조 사이클이 발생합니다. (각각 RC: 2)
john = nil
unit4A = nil
- nil은 할당이 되지만 메모리에서 해제되지는 않습니다 (강한 참조 사이클 발생)
- nil을 할당함으로써 각각의 RC 카운트는 1로 변하지만, 서로에 대한 참조에 대해서는 아직 해제를 함지 않았기 때문에, 메모리에서는 해제가 되지 않습니다.
- 메모리 누수(Memory LeaK)의 상황이 발생
강한 참조 사이클 해결(Memory Leak의 해결 방안)
1. 약한 참조 (Weak Reference)
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person? // 약한 참조
deinit { print("Apartment \(unit) is being deinitialized") }
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
// Prints "John Appleseed is being deinitialized"
unit4A?.tenant // nil
unit4A = nil
// Prints "Apartment 4A is being deinitialized"
- 위의 예제에서는 한쪽만 weak으로 선언해도 문제는 없습니다. 이때, 약한 참조의 경우 참조하고 있던 인스턴스가 사라지면 nil로 초기화됩니다.
2. 비소유 참조(Unowned Reference)
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
- john 변수에 의해 강한 참조를 끊을 때 비소유 customer 참조 때문에 Customer인스턴스에 대한 강한 참조가 발생하지 않습니다.
john = nil
// Prints "John Appleseed is being deinitialized"
// Prints "Card #1234567890123456 is being deinitialized"
- 비소유 참조의 경우, 참조하고 있던 인스턴스가 사라지면, nil로 초기화되지 않습니다.
728x90
'iOS > Swift 문법' 카테고리의 다른 글
에러 처리 (Error Handling) (0) | 2025.03.03 |
---|---|
캡처리스트 (0) | 2025.03.03 |
스위프트 메모리 관리 모델 ARC(Automatic Reference Counting) (0) | 2025.03.03 |
고차함수 (0) | 2025.03.02 |
탈출 클로저(Escaping Closures) / 자동 클로저 (Autoclosures) (0) | 2025.02.28 |