简体   繁体   English

Objective-C中的子类NSArray

[英]Subclass NSArray in Objective-C

I need to have a class, which has all methods of NSArray, which behave the same way, but 2 methods are modified. 我需要一个类,它具有NSArray的所有方法,其行为方式相同,但修改了2个方法。

I want to override these 2 methods in my custom class: 我想在我的自定义类中覆盖这两个方法:

1) countByEnumeratingWithState:objects:count: 1)countByEnumeratingWithState:objects:count:

2) objectAtIndex: 2)objectAtIndex:

After hours of research I don't see any reasonable way to do that, because: 经过数小时的研究,我认为没有任何合理的方法,因为:

  • I don't want to use category, because not all NSArray instances should have the modified behaviour. 我不想使用类别,因为并非所有NSArray实例都应该具有修改后的行为。 (Plus that throws warnings) (加上警告)

  • I don't want to re-write all initializers plus all arrayWith... methods + the primitive methods + implemented my own storage (because this functionality is already implemented in Cocoa, right? Why would I re-implement all the functionality of a class that is already there?) 我不想重写所有初始化程序加上所有的arrayWith ...方法+原始方法+实现我自己的存储(因为这个功能已经在Cocoa中实现了,对不对?为什么我要重新实现一个已经在那里的班级?)

  • If I have my custom class inherit NSObject and use NSArray as storage in an ivar, then all NSArray's methods are not available when programming in Xcode (even if I can forward them to the NSArray ivar) 如果我让自定义类继承NSObject并使用NSArray作为ivar中的存储,那么在Xcode中编程时,所有NSArray的方法都不可用(即使我可以将它们转发到NSArray ivar)

  • I had some success overwriting the method implementations on demand by using method_setImplementation(...), but still can't figure out a way to have dynamically a class created at runtime, which then will have custom implementation of the 2 methods I mentioned. 我通过使用method_setImplementation(...)按需覆盖方法实现取得了一些成功,但仍然无法找到一种方法来动态创建在运行时创建的类,然后将自定义实现我提到的2种方法。

Looking forward to your ideas! 期待您的想法! Thanks 谢谢

Mantra: If something is hard (or seems like it requires more code than is necessary), it is likely that your design is counter to the design principals of the iOS / OS X frameworks. Mantra:如果某些事情很难(或者看起来它需要的代码多于必要的代码),那么您的设计很可能与iOS / OS X框架的设计原理背道而驰。 It may yield a better solution to revisit your design. 它可以为重新审视您的设计提供更好的解决方案。


To answer the original question, if you want to subclass NSArray (or NSMutableArray), you need to implement the primitive methods, no more, no less. 要回答原始问题,如果要子类化NSArray(或NSMutableArray),则需要实现原始方法,不多也不少。

The primitive methods are the methods declared in the @interface of the class itself. 原始方法是在类本身的@interface中声明的方法。 Ie: 即:

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

And for NSMutableArray: 对于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

If you subclass NSMutableArray and implement the above 7 methods (the two from NSArray, too), you will have an NSMutableArray subclass that is compatible -- assuming your methods are correctly implemented -- with all APIs that consume mutable arrays. 如果您继承NSMutableArray并实现上述7个方法(NSArray中的两个方法),那么您将拥有一个兼容的NSMutableArray子类 - 假设您的方法已正确实现 - 所有API都使用可变数组。

This is because of the way class clusters are designed. 这是因为类集群的设计方式。 The public classes are abstract; 公共课是抽象的; are never directly instantiated. 永远不会直接实例化。 They provide a primitive interface that contains the class's core functionality and then concrete implementations of all the other non-primtive API (save for the initializers, see below) that are implemented in terms of the primitives. 它们提供了一个原始接口,它包含类的核心功能,然后是根据原语实现的所有其他非原始API(除了初始化器,见下文)的具体实现。 Concrete, private, subclasses then override all the primitives and some of the non-primitives to provide optimal behaviors for specific configurations. 然后,具体的私有子类覆盖所有基元和一些非基元,以便为特定配置提供最佳行为。

I want to have an NSArray instance for a library I'm working on and I want to have it working transparently for the users of my library. 我想为我正在处理的库创建一个NSArray实例,我想让它为我的库用户透明地工作。 Ie. IE浏览器。 for them should be no difference between using a normal NSArray and the modified class I'll be providing. 对于他们来说,使用普通的NSArray和我将要提供的修改后的类别应该没有区别。 Ie. IE浏览器。 it's a storage concern, which the end users should not be concerned with and the interface should remain the same as NSArray - therefore loosing all init methods is not really an option at that point. 它是一个存储问题,最终用户不应该关注它,并且接口应该保持与NSArray相同 - 因此在这一点上失去所有init方法并不是一个真正的选择。

The initialization methods are not a part of the primitive interface to NSArray . 初始化方法不是 NSArray的原始接口的一部分。 You are adding a requirement above and beyond "make a class compatible with NSArray / NSMutableArray " as defined by the documentation. 您正在添加一个要求,除了文档中定义的“使类与NSArray / NSMutableArray兼容”之外。 Nothing wrong with that, just pointing it out. 没问题,只是指出来。

The reason why this is the case is because it is exceptionally rare to subclass the collection classes to provide the kind of business logic you describe. 之所以出现这种情况,是因为将集合类子类化以提供您描述的业务逻辑非常罕见。 Collections are very generic in their behavior whereas such business logic that conditionalizes collection behavior would be done in a class that manages the overall model layer object graph. 集合在其行为方面非常通用,而条件化集合行为的此类业务逻辑将在管理整个模型层对象图的类中完成。

If you really want to do this, provide an implementation of whatever init* methods you want, calling through to your wrapped generic instance as needed. 如果你真的想这样做,提供你想要的任何init*方法的实现,根据需要调用你的包装通用实例。 There isn't anything so special about the implementations of the initializers that you are going to lose much in doing so. 初始化器的实现没有什么特别之处,你这样做会失去很多。

No need to implement all of them, either. 也不需要实现所有这些。 Implement one or two and @throw a descriptive exception on the rest. 实现一个或两个,并在其余部分上@throw描述性异常。

If you do decide to forward the ones that accept var-args, you can't directly because there are no va_list accepting methods. 如果您决定转发接受var-args的那些,则不能直接,因为没有va_list接受方法。 Instead, you'll want to convert the va_list of arguments into a language array (ie id[] foo = malloc(... * sizeof(id)); ) and pass it to initWithObjects:count: . 相反,您需要将参数的va_list转换为语言数组(即id[] foo = malloc(... * sizeof(id)); )并将其传递给initWithObjects:count: .

Some other comments: 其他一些评论:

  • What you are doing [provide full NS*Array interface in a subclass] seems hard because it is not a common pattern and the framework designers saw no need to create a design to support it. 你正在做什么[在子类中提供完整的NS * Array接口]似乎很难,因为它不是一个常见的模式,框架设计者认为没有必要创建一个支持它的设计。 Custom behaviors at the primitive collection levels are almost always better implemented at a higher level within the object graph. 原始集合级别的自定义行为几乎总是在对象图中的更高级别更好地实现。 Almost always. 几乎总是如此。

  • method_setImplementation() and dynamic class creation is academically interesting, but pretty much never a solution. method_setImplementation()和动态类创建在学术上很有趣,但几乎从来都不是解决方案。 Obviously, mucking with the NSArray or NSMutableArray classes (or the concrete implementation classes) is going to blow up the rest of the frameworks that rely upon standard behavior. 显然,使用NSArray或NSMutableArray类(或具体实现类)进行混乱将会破坏依赖于标准行为的其余框架。 Beyond that it, it is a pattern of dynamic OO composition that is not really intended to be used in Objective-C; 除此之外,它是一种动态OO组合模式,并不是真正用于Objective-C; it'll be a pain in the ass to maintain. 维持这个屁股会很痛苦。

Instead of subclassing NSArray why not create a new class based on NSObject that contains an NSArray? 而不是子类化NSArray为什么不创建一个基于包含NSArray的NSObject的新类?

Then you can use all the functions of the NSArray and add your own methods that will do custom actions with it? 然后你可以使用NSArray的所有功能并添加你自己的方法,用它来做自定义操作?

Or do you NEED an NSArray? 或者你需要一个NSArray?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM