比方說,我有classA
財產A
和財產B
上classB
,我想classAB
有兩個屬性A
和B
。我仍然不知道如何使這一切與組成工作。班級作文在iOS中如何工作?
我意識到這可以通過繼承完成,但我想學習如何使用組合來做到這一點。我已經看過例子,但是我仍然不明白它是如何工作的。
比方說,我有classA
財產A
和財產B
上classB
,我想classAB
有兩個屬性A
和B
。我仍然不知道如何使這一切與組成工作。班級作文在iOS中如何工作?
我意識到這可以通過繼承完成,但我想學習如何使用組合來做到這一點。我已經看過例子,但是我仍然不明白它是如何工作的。
您創建了一個新的類,它具有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消息發送到你的對象沒有關聯的方法,並將它們轉發給另一個對象。如果您正在編寫將構成另一個類的類,或者有許多不同的消息需要轉發並且您不想手動將其全部寫出,則此技巧非常有用。
使用消息轉發的缺點是您放棄了一些控制,並且可能很難預測消息何時由您的類或轉發類處理。例如,如果一個超類實現了一個方法,那麼該方法將被執行,並且轉發代碼將不會被調用。
假設ClassA
和ClassB
按照你說的那樣實現,這很好地工作,並且很容易擴展。
@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;
}
哦,理查德J.羅斯三世,你是如此經常在我這麼做之前張貼我的想法?通常我會及時注意到避免點擊按鈕...可能值得明確指出的是,如果您使用'ab'鍵入'ClassA',那麼對於所有定義的方法而言,它的行爲完全像'ClassA'的實例和屬性,如果你把它轉換成'ClassB',那麼對於所有定義的方法和屬性,它們的行爲都不會同樣由'ClassA'定義? – Tommy 2012-03-14 21:37:35
@Tommy它一定是我的忍者感覺:) – 2012-03-14 21:40:02
@Tommy實際上是不正確的,如果'ClassAB'實現了'ClassA'的選擇器,在這種情況下'ClassAB'實現將被調用(例如,一個自定義'-description'實現)。 – 2012-03-14 21:41:56
@傑克遜在接受這個答案之前,讓我寫一些與KVO相關的東西,讓您以更優雅的方式做到這一點。 – 2012-03-14 21:26:50
我相信這是更好的可讀性解決方案。理查茲解決方案是一個巧妙的技巧,但我總是把實用主義和可讀性放在棘手的代碼上。風格的問題我猜 – Slappy 2012-03-14 22:04:22
@Slappy我曾經使用過本質上是Richard的方法 - 當我有一些我不能修改的代碼時,我必須通過一個'NSString'(這是一個類集羣,所以對它進行子類化並不是微不足道的),我希望通信邊帶。運行時的關聯對象是考慮的主要替代方法,但我認爲'forwardingTargetForSelector:'(儘管創建假裝子類而不是在我的情況下構成)是更清晰和更可讀的解決方案。 – Tommy 2012-03-14 23:01:18