편의상 RC(Reference Count, 참조카운트) 라고 작성하였습니다.
예제를 진행하기 전에 혹은 아래의 글을 읽다가
'클래스, 인스턴스, 객체'가 무엇인지 잘 모르겠다면 여기를 !
'strong, weak, unowned' 키워드가 무엇인지 잘 모르겠다면 여기를 !
'ARC와 RetainCycle'이 무엇인지 잘 모르겠다면 여기를 !
swift파일을 하나 생성하여
모델을 생성 아래와 같이 생성하였습니다!
두 모델 Person, Mac은 서로의 타입의 프로퍼티를 가지고 있습니다.
(사람은 맥북을 소유하고있고, 맥북은 주인이 존재한다! 의 느낌입니다.)
그리고 다시 ViewController로 넘어와서
다음과 같이 각각 Person, Mac 타입의 변수를 선언해주고
시작을 해봅시다!
[ 서로를 참조하지 않을 때 ]
서로를 참조하는 프로퍼티에는 nil값을 대입해 객체를 생성하고
위에서 선언한 변수에 대입해주었습니다.
이때 아래와 같이
keen과 m1Pro 에 각각 nil을 대입하여 메모리에서 해제 시키면
어떻게 될까요??
보기를 드리겠습니다.
1. deinit이 호출되며 print문이 출력된다.
2. 아무 일도 일어나지 않는다.
.
.
.
.
결과는?
두 객체 모두 deinit의 print문이 정상적으로 출력되면서
메모리에서 잘 해제되었음을 유추할 수 있죠.
지금의 관계를 그림으로 표현해보면 다음과 같습니다.
- keen에 Person 인스턴스를 대입할 때 RC가 1 증가합니다. (RC +1)
( -> 생성한 Person 클래스 인스턴스의 메모리 주소를 참조하고 있기에 ) - Person의 mac과 Mac의 owner는 각각 nil이 할당되어있기 때문에 서로를 참조하고 있지않아 RC가 증가하지 않고
- 각각의 인스턴스에 nil을 할당하면 (RC -1)
- RC가 0이 되며 메모리에서 정상적으로 해제가 됩니다.
[ 서로를 참조할 때 ]
그럼 이번엔 두 객체를 참조하는 프로퍼티에 값을 줘볼까요?
assignProperties()라는 함수를 만들어
createaObjects()를 한 다음에 nil이 었던 mac과 owner 프로퍼티에 서로의 객체를 대입해줍니다.
실행 하면 어떻게 될까요?
아까와 보기는 같습니다.
1. deinit이 호출되며 print문이 출력된다.
2. 아무 일도 일어나지 않는다.
.
.
.
.
실행 결과는 아래와 같습니다.
아무리 기다려도 아무 것도 프린트 되고 있지 않죠?
이 말은 deinit이 되지 않았다는 것인데요
(왜나면 deinit이 되면 print문이 출력되어야 하니까)
다음을 그림으로 그려보면
이유를 이해하기 쉬울 것입니다.
Person의 인스턴스인 keen은 m1Pro를 참조하고 있고
Mac의 인스턴스인 m1Pro는 keen을 참조하고 있습니다.
이렇게 서로를 참조하고 있을 때
RC는 2가 됩니다.
- keen에 Person클래스 인스턴스를 대입합니다. (RC +1)
- Person인스턴스의 mac프로퍼티에 m1Pro 인스턴스를 대입합니다. (RC +1)
- keen = nil 을 대입하여 메모리에서 해제시키려합니다. (RC -1)
(m1Pro의 경우도 같습니다.)
최종적으로 RC = 1 이 남게 됩니다.
RC가 0이 아니면 ARC는 메모리에서 해제 시키지 않습니다.
[ 강한 순환 참조를 막는 방법은? ]
결론 부터 말하면 weak, unowned 키워드를 사용하면 됩니다.
지금은 weak을 사용해볼게요
[ unowned 키워드에 대해 간단 설명 ]
- weak 과 마찬가지로 RC를 증가시키지 않습니다.
- unowned는 다른 인스턴스와 생명주기가 같거나 더 긴 경우에 사용하곤 합니다.
- weak은 nil일 수도 아닐 수도 있기에 옵셔널 값을 갖고
unwoned는 항상 값을 가지고 있다고 가정하고 nil이 될 수 없다는 차이점이 있습니다.
owner 를 weak으로 선언하면 RC를 증가시키지 않기 때문에
keen이 메모리에서 해제가 되면 m1Pro의 owner도 자동으로 해제될 것입니다.
직접 확인해보겠습니다
서로를 강하게 참조하고 있기 때문에 생기는 문제이므로
owner 프로퍼티를 weak으로 선언해주어
RC를 증가시키지 않고 메모리에서 해제되면 사라지도록 해주면 됩니다.
다음과 같이 keen에 nil을 할당했을 때
메모리에서 잘 해제가 되었음을 알 수 있는 deinit의 print문이 출력되었고
m1Pro의 owner 프로퍼티 또한 nil이 되어있는 것을 확인할 수 있습니다.
(weak으로 선언하지 않은 상태에서 m1Pro?.owner를 프린트해보면 더 이해가 잘 되실겁니다.)
필요시 프로젝트를 업로드한 깃헙 링크를 참고해주세요 :)
'iOS' 카테고리의 다른 글
[iOS] present를 push처럼, dismiss를 pop 처럼 (4) | 2022.07.11 |
---|---|
iOS 에서의 MVC, MVP, MVVM 변천사 간단 정리 - iOS (0) | 2022.05.05 |
Push Notification 과 APNS - iOS (0) | 2022.04.14 |
[ScrollView] Auto Layout 설정이 어렵다면 이걸 보세요! - iOS (1) | 2021.11.18 |
github에 올리면 안되는 APIKEY 숨기기 - iOS (10) | 2021.10.26 |