iOS/Objective-C

Objective-C) ARC와 Toll-Free Bridging

소들이 2020. 11. 30. 18:23

 

 

 

안녕하세요 :)

오늘은 오랜만에 Objective-C에 대해 다뤄보려고 해요!!!!

제가 퇴사를 하게 되어, 앞으로 Objective-C로 코딩할 일이 많지 않을 것 같아서

까먹지 않기 위해 당분간은 Objective-C에 대한 포스팅도 해보려고 합니다 ㅎㅎㅎ

오늘은 그 중에서 ARC와 Toll-Free Bridging에 대해 다룰 거예요 :D

 

Toll-Free Bridging.......이라... 언제 들어 봤냐면

Swfit에서 String은 왜 Heap에 저장될까........ 에 대해 고찰할 때

String 과 NSString은 Toll-Free Bridging 된다고 말한 적 있어요!!!!!

 

오늘은 이에 대해 조금 더 자세하게 (물론 전지적 옵젝씨 관점에서)

메모리 관점에서 살펴보려고 합니다!!!!

 

모든 포스팅은 편의 말투로 합니다~!!

 

 

 

1. NSType vs CFType

 

우리가 Objective-C로 개발을 하다보면, 

거의 대부분 NS로 시작되는 타입을 사용하지만, 가끔은 CF로 시작되는 타입도 사용하게 됨

이 NS와 CF의 차이점이 무엇이냐면,

 

 

NSType

CFType

특징

Core Foundation 범주에 속한 클래스로, NSObject를 상속받고 있다 

Core Foundation Type으로 C로 구현된 타입으로 클래스가 없다

Reference Count

ARC에 의해 관리된다

C함수들과 구조체 타입으로만 구성되어 있기 때문에,

CFRetain(), CFRelease()수동으로 호출해줘야 한다.

 

 

그러하다

NS는 우리가 잘 알듯 Core Foundation에 속해 있어서

ARC로 설정하면 Reference Counting을 자동으로 해서 retain/release를 해줌!

 

그러나 CFType은 C언어로 구현되어 있어 구조체 타입 & 함수로 이루어져 있고,

따라서 retain/release를 할 때 직접 함수를 호출해서 수동으로 해줘야 함

 

이 개념을 알고가야함 :)

 

 

 

 

2. Toll-Free Bridging

 

그렇다면, Toll-Free Bridging이 무엇이냐

앞서 살펴본 NSType과 CFType은 서로 비슷한 타입이 존재함

 

NSArray & CFArray

NSDictionary & CFDictionary

NSStream & CFStream

 

등등...

이렇게 비슷한 타입들은 서로 간에 타입 캐스팅이 되어,

타입 캐스팅을 통해 서로 왔다 갔다 할 수 있음!!!!

 

예로 NSArray는 타입 캐스팅을 통해 CFArray로 사용할 수있고,

반대로 CFArray도 타입 캐스팅을 통해 NSArray로 사용할 수 있음!!

 

이렇게 타입 캐스팅 되는 것을

 

Toll-Free Bridging

 

이라고 부르는데,

Toll-Free라고 부르는 이유는 서로 다른 Type이지만,

아무런 비용 없이 캐스팅할 수 있다 하여 Toll-Free가 붙은 것임 ㅎㅎ

 

Toll-Free Bridging을 하는 방법은 간단함

 

 

(__bridge Type *)

 

보통 일반적으로 이런 식으로 함 ㅎㅎㅎㅎ 

CFString을 NSString으로 Toll-Free Bridging 한다고 하면

 

 

CFStringRef cfStr = CFSTR("Sodeul");
NSString *nsStr = (__bridge NSString *)(cfStr);

 

이런 식으로 사용해주면 됨!!!

 

 

 

 

3. Toll-Free Bridging 한 경우, Reference Count는 누구 것을 따르나요?

 

앞서 말했듯 NSType과 CFType은 서로 Reference Count를 관리하는 방법이 달랐음

따라서 이렇게 Toll-Free Bridging을 할 경우,

 

ARC가 메모리를 해제해 주느냐, CF 방식대로 메모리를 해제해 주느냐

 

라는 문제점이 있음!!!!

이때, 이 메모리 관리를 어떻게 할 것이냐 때문에 Toll-Free Bridging을 선언하는 방식

위에서 알려준 방식 외에도 두 가지가 더 존재하는데,

 

먼저,

NSString <-> CFString을 예제로 들면서

위에서 설알려준 가장 흔하게 사용하는 방식부터 설명해 주겠음

 

 

 

3-1. __ bridge

 

 

(__bridge Type *)

 

위에서 알려준 가장 흔하게 사용하는 이 방식은,

메모리 해제 책임을 어떻게 가지는지 설명해보겠음 :)

 

 

① NSType ▶ CFType

 

ARC가 메모리 해지 책임을 갖는다

 

 

NSString *nsStr = @"Sodeul";
CFStringRef cfStr = (__bridge CFStringRef)(nsStr);

 

이런 경우엔

ARC가 메모리 해지 책임을 갖기 때문에, CFRelease 함수를 호출해주지 않아도 됨

(우리가 평소 작성 하듯이 ARC가 자동으로 해제해줌)

 

 

② CFType ▶ NSType

 

Core Foundation 방법으로 수동으로 메모리를 해제해줘야 한다

 

CFStringRef cfStr = CFSTR("Sodeul");
NSString *nsStr = (__bridge NSString *)(cfStr);

 

이런 경우엔

Core Foundation 방식으로 메모리를 해제 해줘야 하고,

따라서 다 사용하고 난 뒤에는

 

 

CFRelease(cfStr);

 

이런 식으로 CFRelease 함수를 호출해주어야 함 :))

 

 

 

3-2. __bridge_transfer

 

NSType ▶ CFType 인 경우에만 사용한다

메모리 관리 책임을 ARC에게 넘겨버린다

 

 

NSString *nsStr = @"Sodeul";
CFStringRef cfStr = (__bridge_transfer CFStringRef)(nsStr);

 

이 __bridge_transfer은 CFBridgingRelease라는 함수로 대체해서 쓸 수 있음!!!

CFStringRef cfStr = CFSTR("Sodeul");
NSString *nsStr = CFBridgingRelease(cfStr);

 

이렇게 사용 가능 ㅎㅎㅎㅎㅎㅎ

마찬가지로 ARC에게 넘기기 떄문에 CFRelease() 함수를 호출하지 않음

 

 

 

3-3. __bridge_retain

 

CFType ▶ NSType 인 경우에만 사용한다

Core Foundation 방법으로 수동으로 메모리를 해제해줘야 한다

 

 

CFStringRef cfStr = CFSTR("Sodeul");
NSString *nsStr = (__bridge NSString *)(cfStr);

CFRelease(cfStr);

 

 

이 __bridge_retain은 CFBridgingRetain 함수로 대체해서 쓸 수 있음

 

 

CFStringRef cfStr = CFSTR("Sodeul");
NSString *nsStr = CFBridgingRetain(cfStr);

CFRelease(cfStr);

 

이렇게 사용함 ㅎㅎㅎㅎㅎ

마찬가지로 다 사용하고 난 후엔 CFRelease() 함수를 호출해줘야 함

 

 

 

 

.

.

.

흠...... 그냥 __bridge 쓰면 되는 겅 아닌가...?

__bridge_retain + __bridge_transfer 합친게 __bridge 아님..?

 

이 부분에 대해선 더 공부하고

뭐가 다른지, 같은 건지 알게되면 추가 하겠음 😂

 

 

썸네이 없길래 투척ㅋ