3

我正在尝试为 NSCoding 协议创建一个通用实现。代码将被包裹在一个宏中,该宏将实现 NSCoding。为了实现协议,我们需要两个函数:

-(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];它不会编译,因为initWithCoder:当我们在一个它的 super 没有实现 NSCoding 的类中使用时 super 没有响应。将 super 转换为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]?

只需创建宏的两种变体——一种用于超类采用的类型NSCoding,另一种用于不采用的类型。

要么这样,要么从你自己抽象细节并从中间类型派生出来,这些类型从你的基础中抽象出条件并采用NSCopying——然后你可以调用initWithCoder:任何这样的类型。

于 2012-08-24T21:53:06.847 回答