-
[TIL] 참조와 캡쳐iOS/Swift 2022. 1. 11. 18:21
일단 weak, unowned 키워드에 대해 배우고 캡쳐까지 확장했다.
참조 카운트, ARC에 대한 키워드인데, 이것을 이해하려면 참조 카운트에 대한 이해가 필요하다.
매우 장황한 주제지만, 하나씩 차근차근 공부해보며 작성해봐야겠다.
참조카운트(Reference Count)
간단하게 객체가 참조되고있는 개수를 표현한 용어이다.
객체를 생성하기만 해도 참조가 생기기 때문에 기본적으로 RC는 1이라고 볼 수 있다.
RC가 0이라는 것은 더이상 아무도 그 객체를 필요로하지 않는다는 뜻이기 때문에 메모리 해제를 해 주어야 한다.
이런 상황에서 메모리 해제를 OBJ-C에서는 직접 해줬다고 하는데,, C++을 사용하는 느낌이였을 것 같다.
직접 메모리 관리를 해주는 것을 MRC(Manual Reference Counting)이라고 부른다.
레거시코드를 봐야할 일이 아니면 몰
라도 되기 때문에 넘어가도 될 것 같다.
적용범위? 대상?
참조카운트는
메모리 관리
와 관련된 용어라고 앞에서 말하였다. 즉 Heap영역과 관련이 있다.Swift Heap영역에 생성되는, 즉 Refernce Type은 Class가 있다.
나머지 Struct, Enum은 이번 주제의 대상이 아니다.
Reference counting applies only to instances of classes. Structures and enumerations are value types, not reference types, and aren’t stored and passed by reference.
ARC DocumentARC
ARC의 작동방법을 알기 위해서는 왜 나왔는지부터 알아야 할 것 같다.
위에서 말했듯이 OBJ-C에서는 MRC의 방법을 사용했다고 한다. MRC는 코드에 직접 alloc, new, copy, release와 같은 키워드로 메모리 할당,
해제를 해 주는 방법이다. 이런 번거로움을 줄이기 위해서 ARC가 나왔으니, 어떤 마법을 부려서 자동으로 RC가 관리되는것이 아니라 MRC의 방법을 컴퓨터가
대신 해주겠구나 하고 생각하면 될 것 같다.
포프님에게 이런식으로 생각하라고 배웠다.즉, ARC는 메모리 할당, 해제해주는 코드를 우리 대신해서 삽입해준다. 그것이 컴파일 타임에 일어나고, 런타임에 일어나는 GC(Garbage Collector)와는
다르다고 볼 수 있다.
Instead of you having to remember when to use retain, release, and autorelease, ARC evaluates the lifetime requirements of your objects and automatically inserts appropriate memory management calls for you at compile time.
Transitioning to ARC Release Notes최근에 ComplieTime과 Runtime에서 일어나는 일들이 성능에 얼마나 영향을 미치는지에 대해서 공부한 것이 있다.
당연히
ComplieTime
에 무언가 일어나는것이 속도측면에서 더 좋다. 이것과 관련된 용어로는Static Dispatch
가 있다.마찬가지로 런타임에서 작동하는 GC와는 다르게 ARC는 컴파일타임에 동작하기 때문에 성능면에서 더 좋을 것이다.
불리한점은 나중에 한번 더 찾아봐야겠다.
strong, weak, unowned
참조의 기본적인 방법은 strong이다. 그래서 아무것도 명시하지 않았을 때에는 strong의 방법으로 참조가 일어난다.
Strong
strong은 Reference Count를 증가시킨다.
평소에는 아무 문제가 없지만, Strong Reference Cycle이나 캡쳐를 하는 상황에서 메모리 누수라는 문제가 발생한다.
이런 문제를 해결하기 위해서 weak, unowned가 나왔을 것이라고 생각한다.
Weak, Unowned
둘 다 Reference Count를 증가시키지 않는다.
weak var person = Person()
위와 같이 Person()객체를 생성한다고 해도 RC가 증가하지 않는다는 말이다.
그런데 위 코드는 문제가 있다.
Class나 Struct의 property로써 weak를 사용하지 않고, variable로써 사용하면 할당하는 즉시 nil이 된다.
Reference Count가 증가하지 않기 때문에 할당을 하더라도 RC는 0이다. 즉 ARC에 의해 메모리가 해제된다.
위 예시로 RC가 증가하지 않는다는 것이 어떤 의미인지 좀 이해할 수 있을 것 같다.
이제,
weak
와unowned
의 차이점을 알아보자.차이점은 단 한개,
weak
로 할당된 객체는 Optional이고,unowned
로 할당된 객체는 unOptional이다.이 차이점으로 인해서
unowned
보다는weak
를 주로 사용하는데, 이게 왜 중요한지 생각해보자.참조하고 있는 객체가 사라졌을 때를 생각해 보면 되는데,
weak
는 객체를 Optional로 받아오기 때문에, 해당 객체가 nil일 때 guard에서 막히던, Optional Chaining중간에 막혀서 종료된다.즉 없는 객체에 접근할 걱정이 없다.
하지만
unowned
는 객체가 Optional이 아니라는 가정을 하고있기 때문에, 해당 객체가 nil일때에도 접근을 시도한다.이 때 치명적인오류가 발생하게 된다.
그럼에도 unowned
Unlike a weak reference, however, an unowned reference is used when the other instance has the same lifetime or a longer lifetime.
ARC documents그럼에도 unowned를 사용하는 곳은 존재한다. 위와같이 lifetime이 비슷하거나 다른 객체의 lifetime이 더 길 때, unowned를 사용한다고 한다.
그렇게 하면 굳이 번거롭게 unwrapping을 하지 않아도 되기 때문이다.
캡쳐에 대해서
value capture [value], reference capture ( class, closure ) -> weak, unowned
참고
https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html
'iOS > Swift' 카테고리의 다른 글
[Swift] Protocol에서 Method dispatch (0) 2022.08.21 [Swift] Method dispatch와 V-Table (0) 2022.08.20 [백준] 18258 큐 2 - Swift (0) 2022.06.10 [Swift Grammar] Guard구문에서의 non-Optional 선언 (0) 2022.05.11 [TIL] COW(Copy on Write) (0) 2022.01.10