iOS의 CF와 OC 간 유형 변환

56694 단어
Xcode 4.2 ARC 메커니즘 도입을 시작한 후 Apple은 대상 간의 전환을 지원하기 위해 많은 전환용 키워드를 추가했다.이 강의를 통해 우리는 그 용법과 발생한 이유를 이해할 수 있다.

도입부


ARC가 올바르지 않을 때 id 형식을 void* 형식으로 쓰는 방법을 살펴보겠습니다.

  
  
  
  
  1. id obj = [[NSObject alloc] init];
  2. void *p = obj;

반대로void* 대상을 id 형식으로 되돌릴 때 간단하게 아래로 쓰기만 하고

  
  
  
  
  1. id obj = p;
  2. [obj release];

그러나 위의 코드가 ARC에 유효할 때 다음 오류가 발생했습니다.

  
  
  
  
  1. error: implicit conversion of an Objective-C pointer
  2. to void *’ is disallowed with ARC
  3. void *p = obj;
  4. ^
  5.  
  6. error: implicit conversion of a non-Objective-C pointer
  7. type void *’ to id is disallowed with ARC
  8. id o = p;
  9. ^

__bridge


이 문제를 해결하기 위해 을 사용합니다bridge 키워드는 id 형식과void* 형식의 상호 변환을 실현합니다.아래의 예를 보아라.

  
  
  
  
  1. id obj = [[NSObject alloc] init];
  2.  
  3. void *p = (__bridge void *)obj;
  4.  
  5. id o = (__bridge id)p;

Objective-C의 객체 유형을bridge에서void* 유형으로 변환 및 사용unsafe_unretained 키워드 수식의 변수는 같습니다.대입된 대상의 소유자는 대상의 생명주기 관리를 명확히 해야 하며 이상하게 접근하는 문제가 발생하지 않도록 해야 한다.
제외bridge 이외에 두 개의bridge 관련 유형 변환 키워드:
__bridge_retained
__bridge_transfer
다음에 우리는 이 두 키워드의 차이를 볼 것이다.

__bridge_retained


먼저 사용하기bridge_retained 키워드의 예제 프로그램:

  
  
  
  
  1. id obj = [[NSObject alloc] init];
  2.  
  3. void *p = (__bridge_retained void *)obj;

이름에서 우리는 그 의미를 이해할 수 있어야 한다. 유형이 변환될 때 그 대상의 소유권도 변환된 후에 변수가 보유하게 된다.ARC 코드가 아닌 경우 다음과 같습니다.

  
  
  
  
  1. id obj = [[NSObject alloc] init];
  2.  
  3. void *p = obj;
  4. [(id)p retain];

대상의 소유권이 보유되었는지 실제적인 예로 검증할 수 있다.

  
  
  
  
  1. void *p = 0;
  2.  
  3. {
  4. id obj = [[NSObject alloc] init];
  5. p = (__bridge_retained void *)obj;
  6. }
  7.  
  8. NSLog(@"class=%@", [(__bridge id)p class]);

괄호의 범위를 벗어나면 p는 유효한 실체를 가리킨다.그가 이 대상의 소유권을 가지고 있다는 것은 그 대상이 정의된 범위를 벗어나서 소각되지 않았다는 것을 설명한다.

__bridge_transfer


반대로 대상의 소유권을 가진 변수를 유형이 바뀐 후 원래의 소유권을 방출하려면 을 사용해야 한다bridge_transfer 키워드.문자가 좀 빙빙 돌았으니, 우리 코드를 한 토막 보는 것이 좋겠다.
ARC가 잘못되었을 때 다음 코드를 써야 할 수도 있습니다.

  
  
  
  
  1. // p
  2. id obj = (id)p;
  3. [obj retain];
  4. [(id)p release];

그러면 ARC가 유효하면 다음 코드로 교체할 수 있습니다.

  
  
  
  
  1. // p
  2. id obj = (__bridge_transfer id)p;

알아볼 수 있어bridge_retained는 컴파일러가 우리를 대신해서retain 조작을 한 것이다.bridge_transfer는 우리를 대신해서release1을 만들었다.

Toll-Free bridged


iOS 세계에는 주로 두 가지 대상이 있는데 그것이 바로 Objective-C 대상과 Core Foundation 대상 0이다.Core Foundation 대상은 주로 C 언어로 이루어진 Core Foundation Framework의 대상이고 그 중에서 대상 인용 계수의 개념도 있다. 단지 Cocoa Framework::Foundation Framework의retain/release가 아니라 자신의 CFRetain/CFRelease 인터페이스이다.
이 두 대상 간에 서로 변환하고 조작할 수 있으며 ARC를 사용하지 않을 때 단순히 C 원인의 유형으로 변환하여 CPU 자원을 소모할 필요가 없기 때문에 Toll-Free bridged라고 부른다.예를 들어 NSArray와 CFArrayRef, NSString과 CFStringRef는 서로 다른 Framework에 속하지만 같은 대상 구조를 가지고 있기 때문에 표준 C의 유형으로 전환할 수 있다.
예를 들어 ARC를 사용하지 않을 때는 다음 코드를 사용합니다.

  
  
  
  
  1. NSString *string = [NSString stringWithFormat:...];
  2. CFStringRef cfString = (CFStringRef)string;

마찬가지로 Core Foundation 유형을 Objective-C 유형으로 변환할 때도 표준 C 유형으로 간단하게 변환하면 된다.
그러나 ARC가 유효하면 다음과 같은 컴파일 오류가 발생합니다.

  
  
  
  
  1. Cast of Objective-C pointer type NSString *’ to C pointer type CFStringRef (aka const struct __CFString *’) requires a bridged cast
  2. Use __bridge to convert directly (no change in ownership)
  3. Use __bridge_retained to make an ARC object available as a +1 CFStringRef (aka const struct __CFString *’)

오류에서 우리가 어떻게 해야 하는지를 제시했다:bridge 또는bridge_retained로 전환하는데 그 차이는 대상의 소유권을 변경하는 것이다.
Objective-C는 ARC가 관리하는 대상이고 Core Foundation은 ARC가 관리하는 대상이 아니기 때문에 일부러 이렇게 전환해야 한다. 이것은 id 유형이void*로 전환되는 것과 같은 개념이다.즉, 이 두 가지 유형(ARC 관리가 있고 ARC 관리가 없음)이 전환될 때 컴파일러가 대상의 소유권을 어떻게 처리하는지 알려줘야 한다.
위의 예에서 사용bridge/__bridge_retained 이후의 코드는 다음과 같습니다.

  
  
  
  
  1. NSString *string = [NSString stringWithFormat:...];
  2. CFStringRef cfString = (__bridge CFStringRef)string;

단순히 유형 전환을 실행했을 뿐 소유권 이전은 이뤄지지 않았다. 즉,string 대상이 풀렸을 때 cfString도 사용할 수 없다는 것이다.

  
  
  
  
  1. NSString *string = [NSString stringWithFormat:...];
  2. CFStringRef cfString = (__bridge_retained CFStringRef)string;
  3. ...
  4. CFRelease(cfString); // Core Foundation ARC , release

사용bridge_retained는 대상 (cfString) 의retain 처리를 변환해서 소유권을 이전할 수 있습니다.string 변수가 풀려도 cfString은 구체적인 대상을 사용할 수 있습니다.다만 Core Foundation의 대상은 ARC의 관리 범주에 속하지 않기 때문에 스스로 release가 필요하다는 점이 있다.
실제로 코어파운드리 내부에서는 코어파운드리 대상 유형과 Objective-C 대상 유형의 상호 전환을 실현하기 위해 아래의 함수를 제공한다.

  
  
  
  
  1. CFTypeRef CFBridgingRetain(id X) {
  2. return (__bridge_retained CFTypeRef)X;
  3. }
  4.  
  5. id CFBridgingRelease(CFTypeRef X) {
  6. return (__bridge_transfer id)X;
  7. }

따라서 대신 CFBridgingRetain을 사용할 수 있습니다.bridge_retained 키워드:

  
  
  
  
  1. NSString *string = [NSString stringWithFormat:...];
  2. CFStringRef cfString = CFBridgingRetain(string);
  3. ...
  4. CFRelease(cfString); // Core Foundation ARC , release。

__bridge_transfer
소유권이 이전되는 동시에 전환 변수는 대상의 소유권을 잃게 된다.Core Foundation 객체 유형을 Objective-C 객체 유형으로 변환할 때bridge_transfer 키워드.

  
  
  
  
  1. CFStringRef cfString = CFStringCreate...();
  2. NSString *string = (__bridge_transfer NSString *)cfString;
  3.  
  4. // CFRelease(cfString); __bridge_transfer , release

마찬가지로, 대신 CFBridgingRelease()를 사용할 수 있습니다.bridge_transfer 키워드.

  
  
  
  
  1. CFStringRef cfString = CFStringCreate...();
  2. NSString *string = CFBridgingRelease(cfString);

총결산


위에서 학습한 바와 같이 우리는 ARC에서 유형 전환의 용법을 알게 되었다. 그러면 우리는 실제 사용에서 어떤 원칙이나 방법에 따라 사용을 구분하는가. 다음은 몇 가지 관건적인 요소를 정리했다.
변환된 유형이 ARC 관리 객체인지 확인
Core Foundation 객체 유형은 ARC 관리 범주에 포함되지 않습니다Cocoa Framework::Foundation 객체 유형(일반적으로 사용되는 Objectie-C 객체 유형)은 ARC의 관리 범주 내
ARC 관리 범위에 포함되지 않은 대상이면release의 책임이 누군지 알아야 한다다양한 객체의 라이프 사이클이 어떻게 됩니까1. id obj를 성명할 때, 사실은 부족한 것으로 를 명시했다strong 수식의 변수이기 때문에 컴파일러가retain 처리를 자동으로 추가했습니다. 따라서bridge_transfer 키워드는 우리에게release 처리만 해 줍니다.

좋은 웹페이지 즐겨찾기