实例变量的类别扩展

时间:2011-02-03 13:57:15

标签: iphone objective-c ios

有没有办法以某种方式模拟类的行为,因为类的实例变量而不是方法?

我有一个ClassA,我希望在使用新方法和其他cllass(ClassB)的ivars扩展后保留其名称。 当然,我可以继承ClassA,但结果类会有不同的名称。

对于方法添加,这不是问题 - 类别将是一个很好的解决方案。

更新: ClassA用作XIB的文件所有者,这些要扩展的字段为IBOutlet。所以我在构建阶段需要它们。

3 个答案:

答案 0 :(得分:6)

由于iPhone使用现代的Objective-C运行时,您可以使用associative references向实例添加数据,而无需声明实例变量。请参阅objc_setAssociatedObject等文档。

如果用标准访问器方法将调用包装到运行时,它将非常容易使用。

答案 1 :(得分:3)

我调查了这个问题围绕associative references(感谢Ole),方法静态变量,方法调整,最后来到这个简单的解决方案(没有运行时的东西)。我只是使用“分类”类来返回指向派生类的指针,当然这可以包含额外的ivars。这样做我获得了一个意想不到的好处:我可以调用super的类方法,这在扩展类别时是不可能的。

类扩展示例(已测试):

<强> ClassA的+ ClassB.h

@protocol _ClassB_Protocol
  @optional // to avoid warnings
- (IBAction) onClick:(id)sender;
  @property (nonatomic, retain) IBOutlet UIButton *aButton;
@end

@interface ClassA (_ClassA_Category) <_ClassB_Protocol>
@end

@interface ClassB: ClassA <_ClassB_Protocol> {
    UIButton *aButton; // _ivar_ to add
}
@end

<强> ClassA的+ ClassB.m

@implementation ClassA (_ClassA_Category)
// this will be called first on [ClassA alloc] or [ClassA allocWithZone:(NSZone *)zone]
+(id) alloc {
    if ([self isEqual: [ClassA class]]) {
        return [ClassB alloc];
    } else {
        return [super alloc];
    }
}
@end


@implementation ClassB: ClassA

@synthesize aButton;

-(void) dealloc {
    [aButton release];

    [super dealloc]; // this is impossible for an ordinary category
}

- (void) onClick:(id)sender {
    // some code here
}

@end

现在我们在同一时间:

  • ClassB“extends”ClassA(类别方式);
  • ClassB继承ClassAClassB可以调用ClassA方法);
  • ClassB可以通过ClassA名称(类别方式)
  • 进行访问

答案 2 :(得分:2)

我将Martin的示例放入一个简单的应用程序,用NSData替换ClassA,用XXData替换ClassB,用getIvar替换onClick,并用:

调用它(Mac OS X 10.6.6,Xcode 4 Final)
NSData * data = [NSData data];
NSLog(@"%@", [data getIvar]);

它失败了“ - [NSConcreteData getIvar]:无法识别的选择器发送到实例”..

它失败,因为上面的代码没有调用NSData类别中的“alloc”(返回指向派生类的指针)。相反,如果显式调用“alloc”,如:

NSData * data = [[NSData alloc] init];
NSLog(@"%@", [data getIvar]);

然后一切都很好。