NSMutableArray addObject: -[__NSArrayI addObject:]: unrecognized selector sent to instance 可变数组添加对象:- [__NSArrayI addObject:]:向实例发送无法识别的选择器

69

我已经试了无数种方法来初始化我的NSMutableArray,但是没有一种方法能够成功。我尝试将它设置为一个新分配和初始化的NSMutableArray,只分配、只初始化变量本身以及我想到的任何组合,但结果始终相同。

这里是代码:

Object.h

NSMutableArray *array;

@property (copy) NSMutableArray *array;

Object.m

@synthesize array;

if ( self.array ) {
    [self.array addObject:anObject];
}
else {
    self.array = [NSMutableArray arrayWithObjects:anObject, nil];
}

注意:在调试时“anObject”在执行时不是nil...

我已经测试了anObject并且初始化工作正常,但是当我尝试向self.array添加addObject时,会出现以下错误:

2010-07-10 11:52:55.499 MyApp[4347:1807] -[__NSArrayI addObject:]: 在0x184480实例中发送未识别的选择器

2010-07-10 11:52:55.508 MyApp[4347:1807] *** 终止应用程序由于未捕获的异常 'NSInvalidArgumentException',原因:'-[__NSArrayI addObject:]: 在0x184480实例中发送未识别的选择器'

有人知道发生了什么问题吗?

9个回答

85

@property (copy) 的合成setter会向数组发送一个 copy 消息,从而导致创建一个不可变的副本。

在这里,你别无选择,只能自己实现setter方法,具体细节可以参考Objective-C指南中的详细说明


绝对正确!我在写帖子的时候意识到了这一点,并在下面发布了我的解决方案。我没有真正考虑重写setter,但在我的情况下,我不需要复制,所以我的解决方案适合我。感谢您的快速回复!- Z@K! - Zak
1
Objective-C指南的链接已损坏。 - johnnieb

76

在校对我的帖子时,我有了一个想法,然后回答了自己的问题。这个解决方案足够晦涩,以至于我决定继续发布帖子并自己回答(这样像我这样的新手就不会卡住了)。

我的错误在于...

@property (copy) NSMutableArray *array;

应该是这样的...

@property (retain) NSMutableArray *array;

我的代码执行方式没有问题,但anObject尝试“复制”NSMutableArray数组的方式有问题,导致了错误。

众所周知...

mutableArray = [mutableArray copy];

在我的经验中,常数不总是(或从未)等于...

mutableArray = [mutableArray mutableCopy];

这就是我的问题来源。通过将@property从(copy)改为(retain),我解决了我的问题。


我曾经遇到过同样的问题,我通过将属性从copy更改为retain来解决了它... @Zak 感谢你的回答。 - Rupesh
1
mutableCopy刚刚救了我的命。 - michaelsnowden

11

我想向Georg Fritzsche致敬。最终我确实需要使用(copy)而不是(retain),如果没有他的帮助,我不知道该怎么做。

//@property (copy) NSMutableArray *array;
@property (nonatomic, copy) NSMutableArray *array; //overridden method is non-atomic as it is coded and should be reflected here.

如果你希望在可变对象上使用(copy),你必须按以下方式覆盖 "setter" 方法...

- (void)setArray:(NSArray *)newArray {

    if ( array != newArray ) { 
        [array release];
        array = [newArray mutableCopy];
//      [array retain]; // unnecessary as noted by Georg Fritzsche
    }

    return;
}

注意:您将收到编译器警告:“不兼容的Objective-C类型初始化'struct NSArray *',期望的是'struct NSMutableArray *'”。我选择将newArray参数声明为(NSArray *),因为您可以任意传递任何数组并正确复制到您的(NSMutableArray *)变量中。如果您希望将newArray参数声明为(NSMutableArray *),则仍需要保留mutableCopy方法以获得所需的结果。

向Georg致敬! Z@K!


1
最后,-mutableCopy 已经返回一个已保留的实例,因此不需要 [array retain] - 参见对象所有权策略 - Georg Fritzsche
非常感谢您,Fritzsche先生。我对那个额外的保留变量很好奇,但它似乎在我的程序中起作用。显然我在其他地方有一个错误。:-/ 您真是了不起,感谢您在这篇帖子上的贡献,无意中也为我的程序做出了贡献;我非常感激您的时间!真诚地, Z@K! - Zak
我的额外保留来自这里... @property (copy) NSArray *anotherArray; @property (nonatomic, copy) NSMutableArray array; 当我将anotherArray设置为array时, anotherArray = array; array = nil; 它会释放anotherArray中的所有对象,尽管在@property上有(copy)。这让我很困惑。我在setter中添加的额外保留抵消了释放。通过更改我的代码,我能够解决它... anotherArray = [array copy]; 简单明了。 - Zak
我最终选择了自己的答案,因为它能够为其他寻找此信息的人提供最好的细节,但我想把所有的功劳归给Georg Fritzsche;这实际上是他的答案重新格式化后的结果... - Zak
你需要使用@synthesize语句,这样它就会为你实现“getter”方法。然后,你将覆盖它创建的“setter”方法,就像上面的例子一样,建立你自己的方法。 - Zak
显示剩余3条评论

4

我有一些指向数据数组的索引,希望按数字顺序排列(出于某种重要原因)。在末尾添加mutableCopy之前程序崩溃了。一直感到困惑,直到我想起使用Objective-C 字面量 @[] 返回一个不可变数组

NSMutableArray *a = [@[@(self.indexA), @(self.indexB)] mutableCopy];
NSLog(@"%@", a);
[indexArray sortUsingComparator: ^(NSNumber *obj1, NSNumber *obj2) {
    return [obj1 compare:obj2];
}];
NSLog(@"%@", a);

谢谢,Zak!

3
我曾经遇到同样的错误,尽管我的属性使用了ARC和我使用NSMutableArray分配了数组。
问题出在我将可变数组进行了归档(因为它包含自定义对象)以备将来使用,但当解码时,它返回的是不可变副本。
希望对任何人有所帮助。

1
尝试将对象添加到实际指向NSArray对象的NSMutableArray类型中导致错误。以下演示代码展示了这种情况:
NSString *test = @"test";
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
[mutableArray addObject:test];
NSArray *immutableArray = [[NSArray alloc] init];
mutableArray = immutableArray;
[mutableArray addObject:test]; // Exception: unrecognized selector

从上面的代码可以很容易地看出,一个子类类型被赋值给了一个超类类型。在Java中,这将立即被标记为错误(类型之间的转换错误),并且问题会相对快速地得到解决。公平地说,Objective-C在尝试执行不兼容的赋值时会发出警告,但是有时候这似乎并不足够,并且结果可能会给开发人员带来真正的痛苦。幸运的是,这次大部分痛苦并不是由我承担的 :P

0
我曾经遇到过类似的错误,提示“未识别的选择器发送给NSMutable array实例”。在经历了很多事情之后,我发现我将我的可变数组作为属性使用,并且没有注意复制和粘贴,这导致了问题。
解决方法是将其更改为强类型(您可以根据需要将其更改为任何其他类型,例如强/弱等)。所以在我的情况下,解决方案是:
@property (strong, nonatomic) NSMutableArray *myMutableArray;
@property (strong, nonatomic) NSMutableArray *myMutableArray;

因此,在复制粘贴时要小心!务必检查一次。


0

我因为一个打字错误而遇到了这个异常,也许能帮助某人节省5分钟的时间:

我写的是:

NSMutableArray *names = [NSArray array];

改为:

NSMutableArray *names = [NSMutableArray array];

编译器对此没有问题,因为NSMutableArray也是NSArray,但在尝试添加对象时会崩溃。

-3

如果数组中的一个对象为空,就会出现此异常。


1
不是这个特定的错误。如果尝试插入一个空对象,会得到不同的异常。 - Brad Larson
除此之外,数组可以很好地包含NSNull。 - stephencelis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接