繁体   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