2011-02-03 71 views
5

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

我有一个ClassA,我想保留它的名字后用新的方法和其他cllass的ivars(ClassB)。 当然,我可以继承ClassA,但生成的类会有不同的名称。

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

UPDATE:ClassA用作文件所有者用于XIB,并且这些字段被扩展是IBOutlet秒。所以我需要在构建阶段。

+0

它有一个新的名字有什么问题?如果你试图破解类继承,那么可能有更好的方法来做你想做的事情! – deanWombourne 2011-02-03 14:12:24

+0

@deanWombourne:请查看更新后的问题。有时候,我们需要不寻常的方法。 – 2011-02-03 14:38:12

回答

3

我已经调查了这个问题玩associative references(感谢Ole),方法静态变量,方法swizzling,最后来到这个简单的解决方案(没有运行时的东西)。我只是简单地使用“分类”类来返回一个指向派生类的指针,这当然可以包含额外的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 “扩展” ClassA(分类方式);
  • ClassB继承ClassAClassB可以调用ClassA方法);
  • ClassB可以通过ClassA名称来访问(分类方式)
6

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

如果使用标准存取方法将调用包装到运行时,它将非常易于使用。

+0

用于运行时级别解决方案。但是,我使用`ClassA`作为**文件所有者**作为XIB,并且这些字段是`IBOutlets`。所以,我需要在构建阶段。对不起,没有指定这个细节。 – 2011-02-03 14:34:20

2

我把马丁的例子为一个平凡的应用程序与NSData的,ClassB的与XXData和的onClick与getIvar更换ClassA的,并调用它(的Mac OS X 10.6 。6时,Xcode 4最终)其中:

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

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

它失败,因为 “黄金” 在NSData的类别(返回指向派生类的指针)不被上面的代码调用。如果明确地调用“alloc”,如:

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

那么一切都很好。