3

NSCodingプロトコルの汎用実装を作成しようとしています。コードは、NSCodingを実装するマクロにラップされます。プロトコルを実装するには、次の2つの関数が必要です。

-(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; 
}

問題のある行は、スーパーがNSCodingを実装していないクラスでを使用するとself = [super initWithCoder:coder];、スーパーが応答しないため、コンパイルされないことです。initWithCoder:スーパーをキャストするNSObject<NSCoding>*と、LLVMコンパイラでは機能しません。

[super performSelector:(initWithCoder:) withObject:coder]super == selfであるため、どちらも機能しません。これにより、無限ループが発生します。

[super initWithCoder:coder]スーパークラスの関数をトリガーし、コンパイルの警告/エラーを生成しない方法で呼び出すにはどうすればよいですか?

4

3 に答える 3

2

+instancesRespondToSelector:スーパークラスがセレクターに応答するかどうかを確認し、objc_msgSendSuper()直接それを呼び出すために使用できます。

#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;
}
于 2012-08-24T21:42:46.083 に答える
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;
}
于 2012-08-24T21:36:02.010 に答える
0

スーパークラスの関数をトリガーし、コンパイルの警告/エラーを生成しない方法で[super initWithCoder:coder]を呼び出すにはどうすればよいですか?

マクロの2つのバリアントを作成するだけです。1つはスーパークラスが採用するタイプ用NSCodingで、もう1つは採用しないタイプ用です。

それか、自分自身から詳細を抽象化し、ベースから条件を抽象化して採用する中間タイプから派生します。そうすれば、そのようなタイプをNSCopying呼び出すことができます。initWithCoder:

于 2012-08-24T21:53:06.847 に答える