2011-02-03 73 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]); 

那麼一切都很好。