簡體   English   中英

Objective-C - 可可類簇的有效子類化

[英]Objective-C - Effective Subclassing of Cocoa Class Clusters

我有一個對象,曾經是一個NSMutableSet,但需要更多的東西附加到它。 顯而易見(顯然不受支持)的事情是將NSMutableSet子類化並添加兩個額外的屬性。 由於NSMutableSet與基本上所有的Cocoa數據結構一樣,是一個類集群,我不能以通常的方式對它進行子類化,因為超類只拋出異常。 這導致我走了幾條路。

第一個路徑是創建一個復合對象,它聲明自己是NSMutableSet的子類,但實際上只是將調用轉發到內部NSMutableSet。 我不想在NSMutableSet上實現每個方法,所以我認為forwardInvocation:將是完成我的任務的好方法。 不幸的是,NSMutableSet的抽象類實現了接口上的所有方法,並且它們的實現拋出異常,所以我從來沒有達到可以轉發調用的程度。

第二條路徑是NSProxy的子類,並從那里轉發調用。 這個解決方案不足以說我需要復制NSMutableSet的接口,除非有辦法聲明“這個類實現這個接口”,我不知道(這很可能是解決方案)。

第三條路徑是在NSMutableSet上創建一個類別,並僅為需要使用它的類導入它,但由於您無法通過類別添加非動態屬性,因此該類別不足。 這導致我在一個類別中使用關聯對象。 我願意承認這是這個用例的正確解決方案,但我希望它不是因為它有點笨重。 它是雙重笨重的,因為我添加的屬性是原始的,所以我必須在設置和獲取關聯時包裝和解包它們(除非有一種方法來關聯我不熟悉的基元)。

本質上,我想要的是在功能上作為NSMutableSet(和所有類集群)的子類行為,但無法找出最佳方法。 謝謝!

試圖繼承Cocoa類集群只會造成很大的傷害。 這似乎是一個好主意,但你會永遠遇到問題。

只需使用NSMutableSet作為第一個成員對象創建一個NSObject。

對Cocoa類集群進行子類化是有點氣餒的。 不無道理。 請不要進入這個崩潰的世界。

您的任何一種解決方案都可行。 我已成功使用NSArrayNSDictionary的第一個路徑,所以我相信它也適用於NSMutableSet 請記住,您不僅需要覆蓋forwardInvocation:還需要覆蓋其他一些方法。 請參閱Apple文檔的Surrogate Objects部分:

雖然轉發模仿繼承,但NSObject類從不混淆這兩者。 像respondsToSelector:和isKindOfClass這樣的方法:只查看繼承層次結構,而不是轉發鏈。

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html

就我而言,我已經覆蓋了:

  • conformsToProtocol:
  • isKindOfClass:
  • isMemberOfClass:
  • respondsToSelector:
  • instancesRespondToSelector:
  • forwardInvocation:
  • methodSignatureForSelector:
  • instanceMethodSignatureForSelector:

isKindOfClass: conformsToProtocol:respondsToSelector:肯定是至關重要的。

我也使用了第三條路徑並取得了良好的效果,但我承認相關的對象API很笨拙。

首先,gnasher729是正確的。 不要對類集群進行子類化。 只是不要這樣做。 你可以做到嗎? 如果我告訴你你做不到,那會不會讓你說服你自己不應該? 如果能幫助你做出正確的選擇,我可以撒謊。

但嚴肅地說,它幾乎總是毫無意義。 是您真正的子類特定類型的一套? 或者它真的有點一套。 考慮NSAttributedString 它不是一種字符串,它有一個字符串。 這幾乎總是更好。

而且,類集群恰好是子類的王室痛苦。

也就是說,正如您已經發現的那樣,將相關值添加到數據結構中通常很好,因為您真正想要的是“嘿,我有一些數據需要與其他數據一起使用”。 包裝變得如此簡單,以至於它不應該讓你失望。 請參閱https://stackoverflow.com/a/14918158/97337

objc_setAssociatedObject(self, animatingKey, @(value), OBJC_ASSOCIATION_RETAIN_NONATOMIC);

通過“一個奇怪的技巧” ,你可以很容易地做到這一點:

@interface NSObject (BoolVal)
@property (nonatomic, readwrite, assign) BOOL boolVal;
@end

@implementation NSObject (BoolVal)

- (BOOL)boolVal {
    return [objc_getAssociatedObject(self, _cmd) boolValue];
}

- (void)setBoolVal:(BOOL)value {
    objc_setAssociatedObject(self, @selector(boolVal), @(value), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

但我還是會回來的,這是否真的是一種集(而不是就像一組)的問題,以及是否真的需要每一個可以發送給一組消息作出響應。 NSAttributedString ,您的實際需求通常比實際需求小得多,並且包含您需要的少數方法通常值得簡單和控制。

為了完整起見,讓我們看看你的第一條道路:

創建一個復合對象的類,它聲明自己是NSMutableSet的子類,但實際上只是將調用轉發到內部NSMutableSet

你可以子類化NSMutableSet嗎? 是的,但是你呢? NSMutableSet的文檔說:

子類注釋

應該沒有必要進行子類化。 如果您需要自定義行為,通常最好考慮組合而不是子類化。

所以權衡一下,如果你想要繼承,請再次參考文檔:

覆蓋的方法

在子類中,您必須覆蓋它們的兩個基本方法:

addObject:

removeObject:

您還必須覆蓋NSSet類的基本方法。

看一下NSSet類文檔,我們發現它的原始方法是:

覆蓋的方法

在子類中,您必須覆蓋其所有基本方法:

count

member:

objectEnumerator

就是這樣,5種方法。

您可以將自己的類定義為NSMutableSet的子類,添加一個實例變量,它是NSMutableSet一個實例,實現5個方法並將它們重定向到set實例,添加您希望的任何init方法,然后添加其他屬性。

如果性能受到關注,則需要權衡重定向這五種方法和訪問相關對象以獲取其他屬性。 您需要進行配置才能解決這個問題,但是當且僅當性能成為問題時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM