有没有办法以某种方式模拟类的行为,因为类的实例变量而不是方法?
我有一个ClassA
,我希望在使用新方法和其他cllass(ClassB
)的ivars扩展后保留其名称。
当然,我可以继承ClassA
,但结果类会有不同的名称。
对于方法添加,这不是问题 - 类别将是一个很好的解决方案。
更新: ClassA
用作XIB的文件所有者,这些要扩展的字段为IBOutlet
。所以我在构建阶段需要它们。
答案 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
继承ClassA
(ClassB
可以调用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]);
然后一切都很好。