【问题标题】:Subclass NSArray in Objective-CObjective-C 中的子类 NSArray
【发布时间】:2012-12-17 19:05:36
【问题描述】:

我需要一个类,它包含 NSArray 的所有方法,它们的行为方式相同,但修改了 2 个方法。

我想在我的自定义类中重写这两个方法:

1) countByEnumeratingWithState:objects:count:

2) objectAtIndex:

经过数小时的研究,我认为没有任何合理的方法可以做到这一点,因为:

  • 我不想使用类别,因为并非所有 NSArray 实例都应该具有修改后的行为。 (加上会引发警告)

  • 我不想重写所有初始化程序以及所有 arrayWith... 方法 + 原始方法 + 实现了我自己的存储(因为这个功能已经在 Cocoa 中实现了,对吧?我为什么要重新 -实现已经存在的类的所有功能?)

  • 如果我让我的自定义类继承 NSObject 并使用 NSArray 作为 ivar 中的存储,那么在 Xcode 中编程时所有 NSArray 的方法都不可用(即使我可以将它们转发到 NSArray ivar)

  • 我通过使用 method_setImplementation(...) 按需覆盖了一些方法实现,但仍然无法找到一种在运行时动态创建类的方法,然后该类将具有自定义实现我提到的两种方法。

期待你的想法!谢谢

【问题讨论】:

  • 实际上不是骗子。另一个问题并没有真正回答 OP 的问题。
  • 我想我只是创建一个包装类。用resolveInstanceMethod、forwardingTargetForSelector等应该可以盲转大部分调用。
  • 回答OP的问题;您只需要重写主要方法即可创建子类。在主@interface 中声明的那些)。基类上的所有其他方法都是根据这些方法实现的。覆盖您需要的自定义行为和/或优化之外的内容。代理包装器是可能的,但相比之下真的很慢。
  • @bbum -- 您必须阅读 NSArray 的详细信息 -- “覆盖的方法”包括一个非常令人生畏的函数列表,具体取决于您的阅读方式。
  • 一篇有用的文章cocoawithlove.com/2008/12/…

标签: objective-c ios nsarray


【解决方案1】:

口头禅:如果某事很难(或者看起来需要的代码比必要的多),那么您的设计很可能与 iOS / OS X 框架的设计原则背道而驰。它可能会产生更好的解决方案来重新审视您的设计。


回答原问题,如果你想继承NSArray(或NSMutableArray),你需要实现原始方法,不多也不少。

原始方法是在类本身的@interface 中声明的方法。即:

@interface NSArray : NSObject
- (NSUInteger)count;
- (id)objectAtIndex:(NSUInteger)index;
@end

对于 NSMutableArray:

@interface NSMutableArray : NSArray
- (void)addObject:(id)anObject;
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)removeLastObject;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
@end

如果您将 NSMutableArray 子类化并实现上述 7 个方法(也来自 NSArray 的两个),您将拥有一个兼容的 NSMutableArray 子类(假设您的方法已正确实现)与使用可变数组的所有 API。

这是因为类集群的设计方式。公共类是抽象的;永远不会直接实例化。它们提供了一个原始接口,其中包含类的核心功能,然后是所有其他非原始 API 的具体实现(除了初始化程序,见下文),这些 API 是根据原语实现的。然后,具体的私有子类会覆盖所有基元和一些非基元,以便为特定配置提供最佳行为。

我想为我正在开发的库创建一个 NSArray 实例 希望让它对我图书馆的用户透明地工作。 IE。 对他们来说,使用普通的 NSArray 和 我将提供的修改后的课程。 IE。这是一个存储问题, 最终用户不应该关心的和界面 应该与 NSArray 保持相同 - 因此失去所有 init 方法 在那个时候并不是一个真正的选择。

初始化方法不是NSArray 的原始接口的一部分。您正在添加一个超出文档定义的“使类与NSArray / NSMutableArray 兼容”的要求。没有错,只是指出来。

之所以会出现这种情况,是因为将集合类子类化以提供您描述的那种业务逻辑非常罕见。集合的行为非常通用,而这种限制集合行为的业务逻辑将在管理整个模型层对象图的类中完成。

如果您真的想这样做,请提供您想要的任何init* 方法的实现,并根据需要调用您包装的通用实例。初始化器的实现并没有什么特别之处,您这样做会损失很多。

也不需要全部实现。实现一两个并@throw 其余的描述性异常。

如果您决定转发接受 var-args 的那些,则不能直接转发,因为没有 va_list 接受方法。相反,您需要将参数的 va_list 转换为语言数组(即id[] foo = malloc(... * sizeof(id));)并将其传递给initWithObjects:count:

其他一些cmets:

  • 您正在做的[在子类中提供完整的 NS*Array 接口] 似乎很难,因为它不是一种常见的模式,而且框架设计者认为没有必要创建支持它的设计。原始集合级别的自定义行为几乎总是在对象图中的更高级别更好地实现。 几乎总是。

  • method_setImplementation() 和动态类创建在学术上很有趣,但几乎从来都不是解决方案。显然,使用 NSArray 或 NSMutableArray 类(或具体的实现类)会破坏其他依赖标准行为的框架。除此之外,它是一种动态 OO 组合模式,并不真正打算在 Objective-C 中使用。维护起来会很痛苦。

【讨论】:

  • 解释得很好,+1。您也可以提及需要重新实现原始方法的技术原因是什么(类集群)。
  • 我必须说,经过几天的考虑,我真的同意你在这里整理的内容。从多年使用 Apple 的经验来看,我一定知道得更清楚——对他们来说,只有一个正确的方法。但是,您发现如果在 Cocoa 中很难做到这一点,那么您就走错了路。我选择子类化,实现原始方法,实现 1 个新的自己的 init 方法并覆盖我想要修改的方法。这不是我想要的 100%,但已经足够接近了。
【解决方案2】:

为什么不创建一个基于包含 NSArray 的 NSObject 的新类,而不是继承 NSArray?

那么您可以使用 NSArray 的所有功能并添加您自己的方法来执行自定义操作吗?

或者你需要一个 NSArray?

【讨论】:

  • 我想为我正在处理的库创建一个 NSArray 实例,并且我想让它对我的库的用户透明地工作。 IE。对于他们来说,使用普通的 NSArray 和我将提供的修改后的类应该没有区别。 IE。这是一个存储问题,最终用户不应该关心它,并且接口应该与 NSArray 保持相同 - 因此,此时放弃所有 init 方法并不是一个真正的选择。
猜你喜欢
  • 1970-01-01
  • 2011-01-20
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-26
相关资源
最近更新 更多