2012-06-13 3 views
5

제 3 자 코드를 통해 프로젝트에 적용 할 때 ARC를 사용하지 않고 아직 처리하지 않았습니다. 모든 ARC 문서를 읽었지만이 질문에 대한 대답을 보지 못했습니다.ARC, non-ARC 및 상속

-fobjc-arc으로 컴파일 된 모듈에 정의 된 클래스가있는 경우이 모듈에서 새 클래스를 파생시킬 수 있습니까? ARC가 활성화되지 않았습니까?

파생 클래스가 루트 클래스의 ivars를 만지려고하지 않는 한 내 마음에 그것은 잘 작동해야합니다. [super dealloc]을 호출하는 dealloc 메서드를 사용하는 경우에도 파생 클래스에서 문제가되지 않습니다.

그리고 다른 점은 무엇입니까? 비 ARC 클래스에서 ARC 가능 클래스를 파생시킬 수 있습니까? 잘 작동해야한다, 그렇지?

보너스 포인트 : 내가 알고 있어야하는 ARC 코드와 비 ARC 코드를 혼합 할 때 어떤 문제가 있습니까?

답변

6

내가 아는 문제점이 없습니다. ARC는 소스 코드 전처리 기와 같은 것으로, 컴파일 중에 메모리 관리 호출을 추가한다는 것을 알아야합니다. 연결 단계에 도달하면 ARC 코드를 ARC가 아닌 코드와 실제로 구분할 수 없습니다. 파생 된 클래스가 올바른 메모리 관리를 갖고 있고 수퍼 클래스가 올바른 메모리 관리를 가지고 있다면 그 결과는 정상적으로 작동합니다 (이것은 지나치게 단순화 된 것이지만 목적을 위해 작동해야합니다).

내가 생각할 수있는 유일한 차이점은 weak 속성을 처리하는 것입니다. 그러나 약한 속성을 가진 ARC와 MRC 코드의 일부 조합을 사용하여 버그가있는 코드에 도달 할 수 있다면 충분히 말할 수는 없습니다.

+0

이것은 합의로 보인다. 당신의 도움을 주셔서 감사합니다. – TomSwift

0

이것은 의견 이었지만, 그것에 대해 생각하면서 나는 그것이 말한 것을 확장하고자합니다.

일반 서브 클래스에서 ARC 클래스를 상속 받으셨습니까? 내 생각 (시도하지 않고도)이 작동하지 않을 것입니다. 첫째, ARC 클래스가 ARC 키워드를 사용하는 공개 속성 또는 ivars를 사용하는 경우 weak과 같이 헤더 파일에서 컴파일하는 동안 오류가 발생한다고 생각합니다. 둘째로, 나는 dealloc이 어떻게 작동하는지 모른다. [super dealloc] 번으로 전화해야하나요? 나는 모른다.

어쨌든 수퍼 클래스가 ARC 인 경우 모든 하위 클래스에서 ARC를 사용하지 않는 이유는 무엇입니까? 전혀 그렇게하는 데 장점이 없습니다.

비 ARC 클래스에서 ARC 사용 가능 클래스를 파생시킬 수 있습니까? 잘 작동해야한다, 그렇지?

나는 그 중 하나는 작동하지 않을 것이라고 말하려고했지만, 나는 잘못했을 것이다. 실제로 모든 것은 NSObject에서 상속 받아야하며 수동 참조는 계산됩니다.

+0

예를 들어 ARC를 사용하는 라이브러리에 연결하고 주 프로젝트를 다시 작성할 수없는 경우와 같이 MRC 코드의 ARC 사용 가능 클래스에서 파생되는 것이 좋습니다. (나는 그것을하고 작동하는 것 같습니다.) ARC에서'[super dealloc] '을 호출 할 수 없다. 나는 컴파일러가 당신을 위해 콜을 삽입한다고 생각한다. – zoul

+0

@zoul - 네, 이것이 우리가 가지고있는 시나리오입니다. 타사 모듈에는 ARC가 필요하지만 자체 모듈에는 ARC를 사용할 준비가되어 있지 않습니다. – TomSwift

+0

또한 ARC 클래스의 비 -ARC 하위 클래스가있는 것이 좋습니다. 특히 하위 클래스가 CF API를 많이 사용해야하는 경우 ARC 코드보다 MRR 코드에서 하위 클래스를 사용하는 것이 더 쉬운 경우가 있습니다. – bbum

0

예, ARC 상위 클래스의 비 ARC 조상과 비 ARC 상위 클래스의 ARC 조상을 모두 구현할 수 있습니다.

사실 ARC는 구문 설탕이거나 컴파일 단계에서 소스 코드를 분석하고 코드에 적절한 [release] 및 [retain] 호출을 삽입하는 전처리 기일뿐입니다. 런타임 수준에서 아무 것도 변경되지 않습니다 (weak 속성 제외).

0

ARC 컴파일러가 아닌 ARC, 당신이 알아서 의미 메모리 관리을 담당하지만 두 경우 모두에서 메모리 관리가 정확히 같은 방식으로 작동합니다 의미 : 객체가 살아 남기해야하는 경우

  • 을 그 분실되는 개체가 더 이상 필요하지 않은 경우
  • (즉 retain가하는 일입니다) 증가 카운터를 유지, 그 유지 카운터를 사용하면 객체에 수행하는 경우
  • (즉 release가하는 일입니다) 참조하기 전에 감소하지만, 아직 죽지 않아야한다. 메소드 결과로 반환해야하므로 (그리고 죽은 객체를 반환하지 않으려는 경우) 나중에 자동 보유 풀에 추가해야합니다 (예 : autorelease의 경우와 같습니다. "나중에 해당 객체에 release을 호출하십시오.")
  • 새로 생성 된 객체의 보유 수는 1입니다.
  • 보유 계수가 0에 도달하면 개체가 해제됩니다.

직접 처리하든 컴파일러가 처리하든 관계없이 아무런 역할을하지 않습니다. 컴파일 후,이 메소드는 ARC와 함께 호출되지만 ARC에서는 컴파일러가 호출 된 메소드를 결정합니다. 몇 가지 추가 마법이 있습니다. ARC는 메소드 결과로 반환 할 때 autorelease 풀에 객체를 추가 할 필요가 항상있는 것은 아니지만 종종 최적화 될 수 있지만 호출자와 호출 된 메소드가 모두 사용중인 경우에만이 마법이 적용되므로주의하지 않아도됩니다. 호; 그 중 하나가 아니라면 보통 autorelease이 사용됩니다 (ARC에서 이전과 똑같이 작동 함).

유일한주의해야 할 것은주기를 유지하는 것입니다. ARC를 사용하든 사용하지 않든, 참조 계산은 보유주기를 처리 할 수 ​​없습니다. 차이점이 없습니다.

함정? 수신자 부담 브리징에주의하십시오. NSString *CFStringRef은 실제로 동일한 것이지만 ARC는 CF 세계에 대해 알지 못하므로 ARC가 NSString을 처리하는 동안 CFString을 처리해야합니다. ARC를 사용할 때 ARC에게 브리지 방법을 알려야합니다.

CFStringRef cfstr = ...; 
NSString * nsstr = (__bridge_transfer NSString *)cfstr; 
// NSString * nsstr = [(NSString *)cfstr autorelease]; 

코드는 위의 "ARC는 그 CFString 개체의 소유권을하고 당신이 그것으로 완료로 즉시 해제 알아서하십시오"를 의미한다. 코드는 아래 주석에 표시된 코드와 같이 동작합니다. 신중하게, cfstr은 적어도 하나 이상의 보유 수를 가져야하며 ARC는 최소한 한 번만 그것을 해제합니다. 라운드 다른 방법 :

NSString * nsstr = ...; 
CFStringRef cfstr = (__bridge_retained CFStringRef)cftr; 
// CFStringRef cfstr = (CFStringRef)[nsstr retain]; 

코드는 위의 의미는 "ARC는 나에게 그 NSString의 소유권을 적어주세요, 나는 그것으로 끝났어요 일단 해제 알아서 할게요." 물론, 당신은 그 약속을 지켜야합니다! 때때로 CFRelease(cfstr)에 전화해야합니다. 그렇지 않으면 메모리가 누출됩니다.

마지막으로 유형 캐스트 ​​인 (__bridge ...)이 있으며 소유권이 이전되지 않았습니다. 캐스팅 결과를 주변에 유지하려고하면 포인터가 매달릴 수 있으므로 이런 종류의 캐스팅은 위험합니다. 일반적으로 ARC 객체가 함수가 반환 될 때까지 ARC가 유지하도록 CF 객체를 기대하는 함수에 ARC 객체를 공급할 때 사용합니다.이 기능을 반환하고 함수의 인자에 의해입니다 전에

doSomethingWithString((__bridge CFStringRef)nsstr); 

ARC가 이제까지 그것을 액세스 더 이상 그 선 아래에 어떤 코드로 언제든지 nsstr를 공개 하였다하더라도, 그것은 확실히 그것을 공개하지 않습니다이 항상 안전 정의가 함수가 반환 될 때까지 계속 살아있을 수 있습니다 (함수가 문자열을 활성 상태로 유지하려는 경우 유지해야하며 ARC는 보유 수가 0이되지 않으므로 ARC가이를 해제 한 후에 할당을 해제하지 않습니다).

가끔 오래된 API와에있는 대부분의 사람들은 ARC를 전달하고 투쟁하는 것 것은, void * 컨텍스트로 객체, 아직 실제로 죽은 간단하다

- (void)doIt { 
    NSDictionary myCallbackContext = ...; 
    [obj doSomethingWithCallbackSelector:@selector(iAmDone:) 
     context:(__bridge_retained void *)myCallbackContext 
    ]; 
    // Bridge cast above makes sure that ARC won't kill 
    // myCallbackContext prior to returning from this method. 
    // Think of: 
    // [obj doSomethingWithCallbackSelector:@selector(iAmDone:) 
    // context:(void *)[myCallbackContext retain] 
    // ]; 
} 

// ... 

- (void)iAmDone:(void *)context { 
    NSDictionary * contextDict = (__bridge_transfer NSDictionary *)context; 
    // Use contextDict as you you like, ARC will release it 
    // prior to returning from this method. Think of: 
    // NSDictionary * contextDict = [(NSDictionary *)context autorelease]; 
} 

그리고 나는 진짜 큰해야 첫눈에 분명하지 않은 당신을위한 잡았다. 다음 코드를 고려하십시오 :

@implementation SomeObject { 
    id _someIVAR; 
} 

- (void)someMethod { 
    id someValue = ...; 
    _someIVAR = someValue; 
} 

이 코드는 ARC 및 비 ARC와 동일하지 않습니다. ARC에서 모든 변수는 기본적으로 강한, 그래서 ARC이 코드는 것 그냥이 코드처럼 동작 :

@interface SomeObject 
    @property (retain,nonatomic) id someIVAR; 
@end 

@implementation SomeObject 

- (void)someMethod { 
    id someValue = ...; 
    self.someIVAR = someValue; 
} 

을 유지합니다 someValue 지정 개체가 살아 유지! 그들은 ARC에서 (단지 포인터, 그들은 아무것도 아닌 ARC에 바르 년대도 strong 또는 weak이기 때문에 속성이, 다른

@interface SomeObject 
    @property (assign,nonatomic) id someIVAR; 
@end 

@implementation SomeObject 

- (void)someMethod { 
    id someValue = ...; 
    self.someIVAR = someValue; 
} 

주 : 비 ARC의 코드는이 같은 동작합니다 __unsafe_unretained라고하며 여기에 키워드는 안전하지 않은입니다.

ivars를 직접 사용하고 setters/getters에서 속성에 액세스하지 않는 코드가있는 경우 ARC가 아닌 값에서 ARC로 전환하면 정상적인 메모리 관리를 사용하는 코드의 유지주기가 발생할 수 있습니다. 반면에 ARC에서 ARC가 아닌 코드로 이동하면 포인터가 매달려 있습니다 (이전 객체에 대한 포인터이지만 객체가 이미 사망했기 때문에 아무데도 가리키고 사용하면 예기치 않은 결과가 발생 함). 전에는 예기치 않게 죽을 수도 있습니다.