Objective-C-可可类簇的有效子类化
我有一个曾经是NSMutableSet的对象,但需要附加更多的东西。显然(显然不受支持)要做的事情是将NSMutableSet子类化,并附加两个属性。因为NSMutableSet,基本上和所有Cocoa数据结构一样,是一个类集群,我不能用通常的方式对它进行子类化,因为超类只是抛出异常。这让我走了好几条路 第一条路径是创建一种复合对象,它将自己声明为NSMutableSet的子类,但实际上只是将调用转发给内部NSMutableSet。我不想在NSMutableSet上实现每个方法,所以我认为Objective-C-可可类簇的有效子类化,objective-c,cocoa,subclass,Objective C,Cocoa,Subclass,我有一个曾经是NSMutableSet的对象,但需要附加更多的东西。显然(显然不受支持)要做的事情是将NSMutableSet子类化,并附加两个属性。因为NSMutableSet,基本上和所有Cocoa数据结构一样,是一个类集群,我不能用通常的方式对它进行子类化,因为超类只是抛出异常。这让我走了好几条路 第一条路径是创建一种复合对象,它将自己声明为NSMutableSet的子类,但实际上只是将调用转发给内部NSMutableSet。我不想在NSMutableSet上实现每个方法,所以我认为for
forwardInvocation:
将是完成任务的一个好方法。不幸的是,NSMutableSet的抽象类实现了接口上的所有方法,并且它们的实现会抛出异常,因此我从未达到可以转发调用的程度
第二条路径是子类NSProxy并从那里转发调用。这个解决方案的不足之处在于,我需要复制NSMutableSet的接口,除非有一种我不知道的声明“这个类实现了这个接口”的方法(很可能就是这个解决方案)
第三种方法是在NSMutableSet上创建一个类别,并仅为需要使用它的类导入它,但这还不够,因为无法通过类别添加非动态属性。这让我在一个类别中使用关联对象。我愿意承认这是这个用例的正确解决方案,但我希望它不是,因为它有点笨重。因为我添加的属性是基本属性,所以在设置和获取关联时,我必须对它们进行包装和展开(除非有方法关联我不熟悉的基本属性)
本质上,我想要的是在功能上表现为NSMutableSet(和所有类集群)的子类的东西,但无法找到最佳方法。谢谢 试图对Cocoa类集群进行子类化只会造成极大的伤害。这似乎是个好主意,但你会永远遇到问题
只需创建一个NSObject,其中NSMutableSet作为第一个成员对象 不鼓励将Cocoa类集群子类化。不是没有理由的。请不要进入这个粗糙的世界 你的任何一个解决方案都会奏效。我已成功地将第一条路径与
NSArray
和NSDictionary
一起使用,因此我相信它也适用于NSMutableSet
。请记住,您不仅需要重写forwardInvocation:
,还需要重写其他一些方法。请参考Apple文档的“代理对象”部分:
尽管转发模仿继承,但NSObject类从不混淆这两者。像respondsToSelector和isKindOfClass这样的方法只查看继承层次结构,而不查看转发链
就我而言,我已经超越了:
conformsToProtocol:
iskindof类:
isMemberOfClass:
响应选择器:
实例响应选择器:
forwardInvocation:
methodSignatureForSelector:
instanceMethodSignatureForSelector:
是类的一种:
,符合协议:
和响应选择器:
无疑是至关重要的
我也使用了第三条路径,效果很好,但我承认关联对象API很笨重。首先,gnasher729是正确的。不要对类集群进行子类化。不要这样做。你能做到吗?如果我告诉你你不能,这会帮助你说服自己不应该这样做吗?如果能帮助你做出正确的选择,我可以撒谎 但严肃地说,这几乎总是毫无意义的。你的子类真的是一种特殊的集合吗?或者它真的有点像一套。考虑<代码> NStestDebug字符串< /代码>。它不是一种弦,它有一根弦。这几乎总是更好 而且,类集群恰好是子类的一大难题 也就是说,正如您已经发现的,将相关值添加到数据结构中通常是很好的,因为您真正想要的是“嘿,我有一些数据需要与其他数据一起处理。”包装变得非常简单,不应该让您真正慢下来。见: 使用,您可以让这一切变得非常简单:
@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
类
@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