2012-03-14 59 views
18

比方說,我有classA財產A和財產BclassB,我想classAB有兩個屬性AB。我仍然不知道如何使這一切與組成工作。班級作文在iOS中如何工作?

我意識到這可以通過繼承完成,但我想學習如何使用組合來做到這一點。我已經看過例子,但是我仍然不明白它是如何工作的。

回答

20

您創建了一個新的類,它具有classA和classB的實例作爲成員變量。然後通過傳遞get/set方法來實現這些屬性。

@interface ClassAB 
{ 
    ClassA *objectA; 
    ClassB *objectB; 
} 
@property (nonatomic,strong) id propertyA; 
@property (nonatomic,strong) id propertyB; 
@end 

@implementation ClassAB 
- (id)propertyA { return objectA.propertyA; } 
- (void)setPropertyA:(id)value { objectA.propertyA = value; } 
- (id)propertyB { return objectB.propertyB; } 
- (void)setPropertyB:(id)value { objectB.propertyB = value; } 
@end 

而這就是組成。有些語言有特殊的語法來做這件事(例如,在Ruby中,你可以包含一組來自一個類/模塊的方法),但Objective-C不允許這樣做。

有一件事你可以在Objective-C中做的是catch消息發送到你的對象沒有關聯的方法,並將它們轉發給另一個對象。如果您正在編寫將構成另一個類的類,或者有許多不同的消息需要轉發並且您不想手動將其全部寫出,則此技巧非常有用。

使用消息轉發的缺點是您放棄了一些控制,並且可能很難預測消息何時由您的類或轉發類處理。例如,如果一個超類實現了一個方法,那麼該方法將被執行,並且轉發代碼將不會被調用。

+0

@傑克遜在接受這個答案之前,讓我寫一些與KVO相關的東西,讓您以更優雅的方式做到這一點。 – 2012-03-14 21:26:50

+2

我相信這是更好的可讀性解決方案。理查茲解決方案是一個巧妙的技巧,但我總是把實用主義和可讀性放在棘手的代碼上。風格的問題我猜 – Slappy 2012-03-14 22:04:22

+0

@Slappy我曾經使用過本質上是Richard的方法 - 當我有一些我不能修改的代碼時,我必須通過一個'NSString'(這是一個類集羣,所以對它進行子類化並不是微不足道的),我希望通信邊帶。運行時的關聯對象是考慮的主要替代方法,但我認爲'forwardingTargetForSelector:'(儘管創建假裝子類而不是在我的情況下構成)是更清晰和更可讀的解決方案。 – Tommy 2012-03-14 23:01:18

8

假設ClassAClassB按照你說的那樣實現,這很好地工作,並且很容易擴展。

@interface ClassAB : NSObject 

@property int a; 
@property int b; 

@property ClassA *aObject; 
@property ClassB *bObject; 

@end 

@implementation ClassAB 

@dynamic a, b; 
@synthesize aObject, bObject; 

-(id) forwardingTargetForSelector:(SEL)aSelector 
{ 
    if ([aObject respondsToSelector:aSelector]) 
     return aObject; 
    else if ([bObject respondsToSelector:aSelector]) 
     return bObject; 

    return nil;  
} 

@end 

int main(int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     ClassA *a = [ClassA new]; 
     ClassB *b = [ClassB new]; 

     ClassAB *ab = [ClassAB new]; 
     ab.aObject = a; 
     ab.bObject = b; 

     ab.a = 10; 
     ab.b = 20; 

     NSLog(@"%i, %i", a.a, b.b); // outputs 10, 20 
    } 
    return 0; 
} 
+0

哦,理查德J.羅斯三世,你是如此經常在我這麼做之前張貼我的想法?通常我會及時注意到避免點擊按鈕...可能值得明確指出的是,如果您使用'ab'鍵入'ClassA',那麼對於所有定義的方法而言,它的行爲完全像'ClassA'的實例和屬性,如果你把它轉換成'ClassB',那麼對於所有定義的方法和屬性,它們的行爲都不會同樣由'ClassA'定義? – Tommy 2012-03-14 21:37:35

+0

@Tommy它一定是我的忍者感覺:) – 2012-03-14 21:40:02

+0

@Tommy實際上是不正確的,如果'ClassAB'實現了'ClassA'的選擇器,在這種情況下'ClassAB'實現將被調用(例如,一個自定義'-description'實現)。 – 2012-03-14 21:41:56