Objective c 我应该为NSMutableArray类创建子类吗

Objective c 我应该为NSMutableArray类创建子类吗,objective-c,cocoa-touch,methods,nsmutablearray,subclass,Objective C,Cocoa Touch,Methods,Nsmutablearray,Subclass,我有一个NSMutableArray对象,我想向其中添加自定义方法。我尝试将NSMutableArray子类化,但在尝试使用count方法获取对象数时,出现了一个错误,即“method only defined for abstract class”。为什么计数方法没有被继承 我在其他地方读到,如果我想使用一些NSMutableArray方法,我必须将它们导入到我的自定义类中。我只想向NSMutableArray类添加一个自定义方法。那么,我应该将NSMutableArray子类化,还是应该做其

我有一个NSMutableArray对象,我想向其中添加自定义方法。我尝试将NSMutableArray子类化,但在尝试使用count方法获取对象数时,出现了一个错误,即“method only defined for abstract class”。为什么计数方法没有被继承


我在其他地方读到,如果我想使用一些NSMutableArray方法,我必须将它们导入到我的自定义类中。我只想向NSMutableArray类添加一个自定义方法。那么,我应该将NSMutableArray子类化,还是应该做其他事情

如果只是添加自定义方法,请使用
NSMutableArray
上的类别。它是一个类集群,所以实现是由未记录的子类提供的。您需要提供一些方法来生成自己的子类。但是,如果您只是添加一个类别,那么您的自定义方法将适用于应用程序中的所有
nsmutablearray


作为比较,这里有一个我不久前写的例子。

Objective-C有一种机制,可以将方法添加到名为的现有类中。这样,您就不必创建自己的子类。

NSMutableArray
不是一个具体的类,它只是类集群的抽象超类。
NSMutableArray
的文档中确实有关于如何子类化的信息,但也强烈建议您不要!仅当您对实际存储有特殊需要时才使用子类

类集群意味着将在运行时选择实际的类。创建为空的数组不能使用与使用1000个项创建的数组相同的类。运行时可以为您选择要使用的实现。实际上,
NSMutableArray
将是桥接的
CFArray
。无需担心,但如果在调试器中检查数组的类型,您可能会看到它,您将永远不会看到
NSArray
,但通常会看到
NSCFArray

如前所述,子类化与扩展类不同。Objective-C具有类别的概念。类别类似于其他编程语言所称的混入

例如,如果希望在
NSMutableArray
上使用方便的方法对属性上的所有成员进行排序,请在.h文件中定义category接口,如下所示:

@interface NSMutableArray (CWFirstnameSort)
-(void)sortObjectsByProperty:(NSString*)propertyName;
@end
其实施将是:

@implementation NSMutableArray (CWFirstnameSort)
-(void)sortObjectsByProperty:(NSString*)propertyName;
{
    NSSortDescriptor* sortDesc = [NSSortDescriptor sortDescriptorWithKey:propertName ascending:YES];
    [self sortUsingDescriptors:[NSArray arrayWithObject:sortDesc]];
}
@end
然后将其简单地用作:

[people sortObjectsByProperty:@"firstName"];

我必须同意节点忍者和佩洛的观点,因为从技术上讲,他们都有权利。事实上,这对我帮助不大

序言: 代码中有许多数组,它们一对一只包含一种不同类型的数据,例如classA、classB、classC

问题: 我可以通过将错误的数组传递给某个选择器来轻松混合数组,因为它们都是NSMUTABLEARRY。没有静态检查,只有运行时检查

解决方案-第一次尝试: 生成NSMutableArray的子类,以便编译器进行静态检查并警告错误的数据类型

这很好,因为当您重载-addObject或-objectAtIndex类型时,即使将错误类型传递给-addObject或-objectAtIndex,编译器也会发出警告。 这是不好的,因为您不能以这种方式实例化NSMutableArray超类

解决方案-第二次尝试: 为NSMutableArray创建某种类型的新(代理)类,例如NSObject,并添加NSMutableArray类型的类成员

这很好,因为当您将错误的类型传递给-addObject或-objectAtIndex时,您可以实例化NSMutableClass和编译器检查

不好的一面是,您需要重载所使用的NSMutableArray的每个选择器,而不仅仅是数组包含的类中不同的选择器

结论
当您构建一些复杂的代码时,在它的数组中有许多类类型,相信我,这是值得尝试的。只需这样做,编译器就向我显示了几个错误,在运行时面对这些错误之前,我无法识别这些错误。甚至更糟糕的是,当最终用户面对它时。

摘自苹果NSArray参考,在覆盖方法部分:

NSArray的任何子类都必须重写原语实例方法count和objectAtIndex:。这些方法必须在为集合元素提供的备份存储上操作。对于此备份存储,您可以使用静态数组、标准NSArray对象或某些其他数据类型或机制。您还可以选择部分或完全覆盖要为其提供替代实现的任何其他NSArray方法

作为旁注,在Objective-C中,没有实际的特性允许您将类声明为抽象类,例如在Java中。因此,他们所做的是从某个方法中调用类似于下面代码的东西,他们希望强制该方法被子类重写。实际上,它们为类提供了“抽象类”语义

此方法定义充当抽象方法,如果未被重写,将引发异常,输出如下:

-SomeAbstractFoodMethod仅为抽象类定义。定义-[YourClassName someAbstractFoodMethod]


这是一个老帖子,但我想我会补充我的经验
@PayloW
的答案是一个很好的答案,我认为它完美地回答了你的问题,但是,没有人真正以相反的方式回答了你的问题,所以我将在这里这样做

是否应该将NSMutableArray(或NSArray)子类化?取决于您想要实现的目标。如果您只想添加一个方法来扩展数组的基本功能,如排序,那么
@PayloW
的答案是
类别
。但是,如果您想创建一个行为类似于数组的自定义类,那么是的,子类化
NSMutableArray
非常简单。但因为它是一个类集群,所以它并不像您期望的那样完全是子类。通常在子类化中,超类中可用的方法对您的
- (void) someAbstractFooMethod
{
    //Force subclassers to override this method
    NSString *methodName = NSStringFromSelector(_cmd);
    NSString *className = [self className];
    [NSException raise:NSInvalidArgumentException
                format:@"-%@ only defined for abstract class. Define -[%@ %@]!", methodName, className, methodName];
}
@interface MyCustomArrayClass : NSMutableArray {

    // Backend instance your class will be using
    NSMutableArray *_backendArray;
}

// *** YOUR CUSTOM METHODS HERE (no need to put the Super's methods here) ***

-(bool)isEmpty;
-(id)nameAtIndex:(int)index;
-(int)rowAtIndex:(int)index;
-(int)columnAtIndex:(int)index;

@end
@implementation MyCustomArrayClass

-(instancetype)init {

    if (self = [super init]) {            
        _backendArray = [@[] mutableCopy];
    }

    return self;
}

// *** Super's Required Methods (because you're going to use them) ***

-(void)addObject:(id)anObject {
    [_backendArray addObject:anObject];
}

-(void)insertObject:(id)anObject atIndex:(NSUInteger)index {
    [_backendArray insertObject:anObject atIndex:index];
}

-(void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {
    [_backendArray replaceObjectAtIndex:index withObject:anObject];
}

-(id)objectAtIndex:(NSUInteger)index {
    return [_backendArray objectAtIndex:index];
}

-(NSUInteger)count {
    return _backendArray.count;
}

-(void)removeObject:(id)anObject {
    [_backendArray removeObject:anObject];
}

-(void)removeLastObject {
    [_backendArray removeLastObject];
}

-(void)removeAllObjects {
    [_backendArray removeAllObjects];
}

-(void)removeObjectAtIndex:(NSUInteger)index {
    [_backendArray removeObjectAtIndex:index];
}

// *** YOUR CUSTOM METHODS ***

-(bool)isEmpty {
    return _backendArray.count == 0;
}

-(id)nameAtIndex:(int)index {
    return ((MyObject *)_backendArray[index]).name;
}

-(int)rowAtIndex:(int)index {
    return ((MyObject *)_backendArray[index]).row;
}

-(int)columnAtIndex:(int)index {
    return ((MyObject *)_backendArray[index]).column;
}

@end
MyCustomArrayClass *customArray = [[MyCustomArrayClass alloc] init];

// Your custom method
int row = [customArray rowAtIndex:10];

// NSMutableArray method
[customArray removeLastObject];

// Your custom class used just like an array !!!
index = 20;
MyObject *obj = customArray[index];