Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective-C-可可类簇的有效子类化_Objective C_Cocoa_Subclass - Fatal编程技术网

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

Objective-C-可可类簇的有效子类化,objective-c,cocoa,subclass,Objective C,Cocoa,Subclass,我有一个曾经是NSMutableSet的对象,但需要附加更多的东西。显然(显然不受支持)要做的事情是将NSMutableSet子类化,并附加两个属性。因为NSMutableSet,基本上和所有Cocoa数据结构一样,是一个类集群,我不能用通常的方式对它进行子类化,因为超类只是抛出异常。这让我走了好几条路 第一条路径是创建一种复合对象,它将自己声明为NSMutableSet的子类,但实际上只是将调用转发给内部NSMutableSet。我不想在NSMutableSet上实现每个方法,所以我认为for

我有一个曾经是NSMutableSet的对象,但需要附加更多的东西。显然(显然不受支持)要做的事情是将NSMutableSet子类化,并附加两个属性。因为NSMutableSet,基本上和所有Cocoa数据结构一样,是一个类集群,我不能用通常的方式对它进行子类化,因为超类只是抛出异常。这让我走了好几条路

第一条路径是创建一种复合对象,它将自己声明为NSMutableSet的子类,但实际上只是将调用转发给内部NSMutableSet。我不想在NSMutableSet上实现每个方法,所以我认为
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