我有一个曾经是NSMutableSet的对象,但还需要一些附加的东西。显而易见(显然不受支持)的事情是将NSMutableSet子类化并添加两个额外的属性。由于NSMutableSet与基本上所有的Cocoa数据结构一样,是一个类集群,我不能以通常的方式对它进行子类化,因为超类只抛出异常。这导致我走了几条路。
第一个路径是创建一个复合对象的类,它声明自己是NSMutableSet的子类,但实际上只是将调用转发到内部NSMutableSet。我不想在NSMutableSet上实现每个方法,所以我认为forwardInvocation:
是完成任务的好方法。不幸的是,NSMutableSet的抽象类实现了接口上的所有方法,并且它们的实现抛出异常,所以我从来没有达到可以转发调用的程度。
第二条路径是NSProxy的子类并从那里转发调用。这个解决方案不足之处在于我需要复制NSMutableSet的接口,除非有一种方法来声明"这个类实现了这个接口"我不知道的(这很可能是解决方案)。
第三条路径是在NSMutableSet上创建一个类别,并仅为需要使用它的类导入它,但由于您无法通过类别添加非动态属性,因此该类别不足。这导致我在一个类别中使用关联对象。我愿意承认这是这个用例的正确解决方案,但我希望它不是因为它有点笨拙。它加倍的笨重,因为我添加的属性是原始的,所以我必须在设置和获取关联时包装和解包它们(除非有'方式关联基元我和# 39; m不熟悉。)
基本上,我想要的是在功能上作为NSMutableSet(和所有类集群)的子类的行为,但无法找出最佳方法。谢谢!
答案 0 :(得分:2)
尝试子类化Cocoa类集群只会造成很大的伤害。这似乎是一个好主意,但你会永远遇到问题。
只需使用NSMutableSet创建一个NSObject作为第一个成员对象。
答案 1 :(得分:2)
对Cocoa类集群进行子类化是有点气馁的。不无道理。请不要进入这个崩溃的世界。
您的任何一种解决方案都可行。我已经成功使用了NSArray
和NSDictionary
的第一条路径,所以我相信它也适用于NSMutableSet
。请记住,您不仅需要覆盖forwardInvocation:
,还需要覆盖其他一些方法。请参阅Apple文档的代理对象部分:
虽然转发模仿继承,但NSObject类从不混淆这两者。像respondsToSelector:和isKindOfClass这样的方法:只查看继承层次结构,而不是转发链。
就我而言,我已经覆盖了:
conformsToProtocol:
isKindOfClass:
isMemberOfClass:
respondsToSelector:
instancesRespondToSelector:
forwardInvocation:
methodSignatureForSelector:
instanceMethodSignatureForSelector:
isKindOfClass:
,conformsToProtocol:
和respondsToSelector:
绝对是至关重要的。
我还使用了第三条路径并取得了良好的效果,但我承认关联的对象API很笨拙。
答案 2 :(得分:2)
首先,gnasher729是正确的。不要对类集群进行子类化。只是不要这样做。你可以做到吗?如果我告诉你你做不到,那会不会让你说服你自己不应该?如果它可以帮助你做出好的选择,我可以撒谎。
但严肃地说,它几乎总是毫无意义。你的子类真的是一个特定的种集吗?或者它真的是喜欢一套。考虑NSAttributedString
。它不是一种字符串,它有一个字符串。这几乎总是更好。
而且,类集群恰好是子类的王室痛苦。
也就是说,正如您已经发现的那样,将相关值添加到数据结构中通常很好,因为您真正想要的是“嘿,我有一些数据需要与其他数据一起使用”。包装变得如此简单,以至于它不应该让你失望。见https://stackoverflow.com/a/14918158/97337:
objc_setAssociatedObject(self, animatingKey, @(value), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
使用"one weird trick",您可以轻松实现这一目标:
@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
一样,您的实际需求通常比实际需求小得多,并且包含您需要的少数方法通常值得简单和控制。
答案 3 :(得分:1)
为了完整起见,让我们看看你的第一条道路:
创建一种复合对象,它声明自己是
NSMutableSet
的子类,但实际上只是将调用转发给内部NSMutableSet
你可以继承NSMutableSet
吗?是的,但是你呢? NSMutableSet
的文档说:
子类注释
应该不需要子类化。如果您需要自定义行为,通常最好考虑组合而不是子类化。
所以权衡一下,如果你想要继承,请再次参考文档:
覆盖的方法
在子类中,您必须覆盖它们的两个基本方法:
addObject:
removeObject:
您还必须覆盖
NSSet
类的原始方法。
查看NSSet
类文档,我们发现它的原始方法是:
覆盖的方法
在子类中,您必须覆盖其所有基本方法:
count
member:
objectEnumerator
这就是它,5种方法。
您可以将自己的类定义为NSMutableSet
的子类,添加一个实例变量,它是NSMutableSet
的一个实例,实现5个方法并将它们重定向到set实例,添加任何init方法你希望,然后添加您的其他属性。
如果关注性能,那么权衡是在重定向这五种方法和访问其他属性的关联对象之间。您需要进行配置才能解决这个问题,但是当且仅当性能成为问题时。