Objective-C 中的 NSArray 子类 [英] Subclass NSArray in Objective-C

查看:50
本文介绍了Objective-C 中的 NSArray 子类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to have a class, which has all methods of NSArray, which behave the same way, but 2 methods are modified.

我想在我的自定义类中覆盖这两个方法:

I want to override these 2 methods in my custom class:

1) countByEnumatingWithState: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:

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

  • I don't want to use category, because not all NSArray instances should have the modified behaviour. (Plus that throws warnings)

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

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?)

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

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)

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

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.

期待你的想法!谢谢

推荐答案

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

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. It may yield a better solution to revisit your design.

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

To answer the original question, if you want to subclass NSArray (or NSMutableArray), you need to implement the primitive methods, no more, no less.

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

The primitive methods are the methods declared in the @interface of the class itself. I.e.:

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

对于 NSMutableArray:

And for 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 兼容.

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.

这是因为类集群的设计方式.公共类是抽象的;永远不会直接实例化.它们提供了一个原始接口,其中包含类的核心功能,然后是所有其他非原始 API(除了初始化器,见下文)的具体实现,这些 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. Concrete, private, subclasses then override all the primitives and some of the non-primitives to provide optimal behaviors for specific configurations.

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

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. Ie. for them should be no difference between using a normal NSArray and the modified class I'll be providing. 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 原始接口的一部分.您正在添加超出文档定义的使类与 NSArray/NSMutableArray 兼容"之外的要求.没有错,只是指出来.

The initialization methods are not a part of the primitive interface to NSArray. You are adding a requirement above and beyond "make a class compatible with NSArray / NSMutableArray" as defined by the documentation. 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.

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

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. There isn't anything so special about the implementations of the initializers that you are going to lose much in doing so.

也不需要全部实现.实现一两个,然后@throw 一个描述性异常.

No need to implement all of them, either. Implement one or two and @throw a descriptive exception on the rest.

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

If you do decide to forward the ones that accept var-args, you can't directly because there are no va_list accepting methods. Instead, you'll want to convert the va_list of arguments into a language array (i.e. id[] foo = malloc(... * sizeof(id));) and pass it to initWithObjects:count:.

其他一些评论:

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

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

method_setImplementation() and dynamic class creation is academically interesting, but pretty much never a solution. 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. Beyond that it, it is a pattern of dynamic OO composition that is not really intended to be used in Objective-C; it'll be a pain in the ass to maintain.

这篇关于Objective-C 中的 NSArray 子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆