2012-08-23 2 views
3

NSCoding 프로토콜에 대한 일반 구현을 만들려고합니다. NSCoding을 구현할 매크로에서 코드가 래핑됩니다.수퍼 클래스에서 선택적 메서드 호출 (Objective-C)

-(void)encodeWithCoder:(NSCoder*)coder; 
-(id)initWithCoder:(NSCoder*)coder; 

는 initWithCoder 기능의 일반적인 구현은 다음과 같습니다 :

-(id)initWithCoder:(NSCoder*)coder { 
    if ([super conformsToProtocol:@protocol(NSCoding)]) 
     self = [super initWithCoder:coder]; 
    else { 
     self = [super init]; 
    } 
    if (!self) return self; 
    self = [MyGenericCoder initWithCoder:coder forObject:self withClass:[__clazz class]]; 
    return self; 
} 

문제가있는 라인은 슈퍼하지 않기 때문에이 컴파일되지 않습니다 self = [super initWithCoder:coder]; 인 프로토콜을 구현하기 위해 , 우리는 두 가지 기능을 필요 super가 NSCoding을 구현하지 않는 클래스에서를 사용할 때 initWithCoder:에 응답하십시오. NSObject<NSCoding>*으로 super를 캐스팅하면 LLVM 컴파일러에서 작동하지 않습니다.

[super performSelector:(initWithCoder:) withObject:coder] 무한 루프가 발생하는 super == self 이후에는 작동하지 않습니다.

수퍼 클래스에서 함수를 트리거하는 방식으로 [super initWithCoder:coder]을 호출하고 컴파일 경고/오류를 생성하지 않으려면 어떻게해야합니까?

+0

'컴파일되지 않습니다.'라는 말은 아마 경고를 받는다는 의미일까요? 관련 컴파일러 옵션을 경고가 오류로 처리하도록 설정하지 않았다면 적어도 컴파일해야한다고 생각합니다. LLVM은 super를'(id) '에 캐스트한다면 어떻게 될까? – Tommy

답변

2

당신은 실제로 전화를 직접 다음 objc_msgSendSuper() 당신의 슈퍼 클래스가 선택에 응답 여부를 확인하기 위해 +instancesRespondToSelector:를 사용하고 있습니다.

#import <objc/message.h> 

- (id)initWithCoder:(NSCoder *)coder { 
    // Note: use [__clazz superclass] directly because we need the 
    // compile-time superclass instead of the runtime superclass. 
    if ([[__clazz superclass] instancesRespondToSelector:_cmd]) { 
     struct objc_super sup = {self, [__clazz superclass]}; 
     ((id(*)(struct objc_super *, SEL, NSCoder*))objc_msgSendSuper)(&sup, _cmd, coder); 
    } else { 
     [super init]; 
    } 
    if (!self) return self; 
    self = [MyGenericCoder initWithCoder:coder forObject:self withClass:[__clazz class]]; 
    return self; 
} 
+0

[내 솔루션] (http://stackoverflow.com/a/12116975/1300347) 런타임에 수퍼 클래스를 찾습니다. 왜 컴파일 시간에 그것을 찾을 필요가 있다고 생각합니까? –

+0

@TomerShiri : 그렇지 않습니다. 매크로에 전달 된'Class'라고 가정하고있는'__clazz'도 참조하고 있습니다. 이것이 컴파일 타임입니다. 주의는 '자기'에 기초하여 그것을 파악하려고 시도하는 것을 피하는 것이었다. –

0
#import <objc/runtime.h> 
-(id)initWithCoder:(NSCoder*)coder { 
    Class superclass = class_getSuperclass([__clazz class]); 
    SEL constructor = @selector(initWithCoder:); 
    if (class_conformsToProtocol(superclass,@protocol(NSCoding))) { 
     self = class_getMethodImplementation(superclass,constructor)(self,constructor,coder); 
    } 
    else { 
     self = [super init]; 
    } 
    if (!self) return self; 
    self = [MyGenericCoder initWithCoder:coder forObject:self withClass:[__clazz class]]; 
    return self; 
} 
0

어떻게 [슈퍼 initWithCoder을 : 코더] 호출 할 수있는 슈퍼 클래스에서 함수를 실행하고 컴파일 경고/오류를 생성하지 않습니다 방식을? 하지 않는 사람들을위한 슈퍼 클래스 NSCoding을 채택 유형의 하나, 또 다른 -

그냥 매크로의 두 가지 변종을 만들 수 있습니다.

자신의 세부 사항을 추상화하고 기지에서 조건을 추상화하고 NSCopying을 채택하는 중간 유형에서 파생 된 경우 - 그런 유형의 전화 번호는 initWithCoder:입니다.

관련 문제