주 내용은 다음에서 발췌하였습니다.
https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html
전 글에서 말했다시피 실제 개발하며 더 빈번하게 retain cycle이 발생할 수 있는 경우에 대해서 글을 쓴다.
이번 글은 객체가 retainCycle이 발생하는 경우에 대해서 알아볼것이다.
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
var tenant: Person?
}
위와 같이 Person은 Apartment를
Apartment는 Person을 property로써 소유하고 있다.
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
이렇게 객체화를 하면 강한 참조는 다음 그림과 같이 형성이 된다.
아직까지 jhon은 아파트를 사지 못한 상태이고 unit4a에는 세입자가 없는 상황이다.
이제 부터 우리의 소망인 내 집 마련(비록 월세,전세지만 ㅠ)을 해주 도록 하자
john!.apartment = unit4A
unit4A!.tenant = john
이렇게 되면 다음과 같이 강한 참조가 형성되게 된다.
딱 봐도 뭔가 순환적으로 강한 참조를 하고 있다.
이것이 바로 문제의 retain cycle이 형성 되는 시점이다 .
현재 시점에서 참조 카운트는 어떻게 될까.
jhon의 Person 객체화 + 1
unit4a의 Apartment 객체화 + 1
jhon의 apartment의 unit4a 참조 + 1
unit4a의 tenant의 jhon 참조 + 1
총 4가 된다.
(실험해보고 싶은 사람은 CFGetRetainCount 함수를 써서 확인해보자!
위의 예시는 이해를 위해 직관적으로 써놓은 것이라 정확하진 않다.)
john = nil
unit4A = nil
위와 같이 john과 unit4a에 nil을 대입하면 어떨까?
전글에서 설명했듯이 ARC는 어떤 한 property라도 특정 객체를 참조 하고 있게 되면 메모리를 해제 하지 않는다.
즉 Person객체와 Apartment객체는 다음과 같이 아직 메모리 상에 남아 있게 된다.
메모리 참조 카운트를 구해보려 했지만 접근 할 수 있는 방법이 없어서 아쉽게도 측정은 하지 못했다.
(혹시 이런상태에서 측정 하는 법 아시는 분 댓글 달아주시면 감사하겠습니다.)
그럼 어떻게 하면 retainCycle을 방지 할 수 있냐 하면 바로 weak, unowned 등을 쓰는 것이다
그렇다면 weak와 unowned의 차이점을 무엇일까?
문서에 따르면 weak는 단순히 strong 참조를 하지 않게 하는 것이다. 따라서 ARC가 참조 객체를 처분하는 것을 막지 않는다.
ARC가 자동으로 weak로 선언 되어 있는 것은 nil로 바꿔버린다.
unowned는 weak와 마찬가지로 강한 참조를 하지 않게 하는 것인데 차이점은 참조하려는 객체가 같은 생명주기를 같거나 혹은 더 긴 생명주기를 갖을때 쓴다.
unowned의 필요성에 대해서 의아해 할 수 있는데 다음과 같은 상황에서 필요하다.
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") }
}
Credit Card의 customer를 weak로 해도 상관 없지만 구문적으로 보면 Credit Card는 Customer가 없으면 존재할 수 없는 것이다.
따라서 weak은 선언할때 optional로 밖에 선언하지 못해서 강제성을 가지지 못하지만 unowned를 쓰면 강제성이 부여되 구문적으로
더 가독성이 있는 코드가 만들어 지는 것이다.
unowned 도 optional로 쓸수 있지만 문서에 정확이 weak와 같은 동작을 한다고 되어 있으므로 굳이 살펴보지 않겠다.
이전 글
https://sm-ios-story.tistory.com/2
다음 글
https://sm-ios-story.tistory.com/4
'iOS' 카테고리의 다른 글
KeyChain vs UserDefaults(1) (0) | 2022.11.17 |
---|---|
some 과 any 그리고 Any?(2) (0) | 2022.10.26 |
some 과 any 그리고 Any?(1) (0) | 2022.10.12 |
ARC란 무엇인가?(3) (0) | 2022.05.21 |
ARC란 무엇인가?(1) (0) | 2022.05.21 |