objective-c“发送到immutable对象的mutating方法”错误

时间:2009-08-03 19:00:19

标签: objective-c nsstring nsmutablearray immutability

我对objective-c很新,并尝试为iphone创建一个小应用程序 我差不多完成了这个小错误。实际上,我已经用谷歌搜索了几个小时来找到合适的解决方案,但不幸的是我无法找到有效的解决方案。
我在这里使用这个教程来构建一个UITableView:UITableView Tutorial 完整的错误消息如下所示:

  

*由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'* - [NSCFArray insertObject:atIndex:]:发送到不可变对象的mutating方法'

这是数据控制器标题: MyLinksDataController.h

@interface MyLinksDataController : NSObject {

NSMutableArray *tableList; //<---important part

}

- (unsigned)countOfList;
- (id)objectInListAtIndex:(unsigned)theIndex;
- (void)addData:(NSString *)data; //<---important part
- (void)removeDataAtIndex:(unsigned)theIndex;

@property (nonatomic, copy, readwrite) NSMutableArray *tableList; //<---important part

.....

数据控制器方法: MyLinksDataController.m

#import "MyLinksDataController.h"

@implementation MyLinksDataController

@synthesize tableList;

- (id)init {

    if (self = [super init]) {

        NSLog(@"Initilizing DataController");
        //Instantiate list
        NSMutableArray *localList = [[NSMutableArray alloc] init];
        self.tableList = [localList copy];
        [localList release];

        //Add initial Data
        [self addData:@"AAAAAAAAAAAAAA"];
        [self addData:@"BBBBBBBBBBBBBB"];

    }

    return self;

}

-------------------------------稍后在源代码中---------- -----------------------

- (void)addData:(NSString*)data; {

    [tableList addObject:data]; //<---- here the app crashes

}

我非常感谢任何帮助。

感谢您的支持。

丹尼尔

5 个答案:

答案 0 :(得分:27)

copy 消息发送到NSMutableArray - 如 init 中的以下语句 - 返回不可变副本。

self.tableList = [localList copy];

Cocoa文档使用单词 immutable 来引用只读,不可更改的初始化对象。因此,对 addObject:的子序列调用失败并显示错误消息。

请注意上面的赋值语句不会触发任何编译器警告。 copy 返回一个 id ,就编译器而言,它非常适合NSMutableArray * tableList。这里也没有运行时错误,因为没有消息传递; NSArray指针只放在NSMutableArray指针变量中。

要获得可变副本,请改用 mutableCopy

请注意, copy mutableCopy 都会创建一个新数组,并将原始内容复制到该数组中。副本中的更改不会反映在原件中。如果您只需要对原始数组的其他引用,请改为使用 retain

您可以在copyWithZone referenceNSMutableCopying protocol reference的讨论部分找到更多详细信息。

答案 1 :(得分:5)

基本上,你正在遇到Cocoa(specifically, these details)的内存管理规则。如果存在具有immutable version和可变版本的对象,则将-copy发送到对象将返回不可变对象。

让我们逐步完成相关部分。

NSMutableArray *localList = [[NSMutableArray alloc] init];

这将创建一个您拥有的新的空可变数组。细

self.tableList = [localList copy];

这将创建空数组的不可变副本。此外,您拥有这个新创建的副本。那是你目前拥有的两个对象。

这也会将您复制的对象分配给tableList属性。让我们看一下财产声明:

@property (nonatomic, copy, readwrite) NSMutableArray *tableList;

此属性使用copy attribute声明,因此无论何时为其分配新值,都会向其发送另一个-copy方法。但是,第三个副本并非由您拥有 - 它由对象拥有。

[localList release];

释放原始的空可变数组。很好,但是仍然有你在第二线上漂浮的那个,没有发布。那是内存泄漏。

如果您确实需要某些内容的可变副本,则需要-mutableCopy方法。 (这些方法的文档位于NSCopyingNSMutableCopying下。)但是,您永远不会在具有copy属性的属性中获取某些内容的可变版本,因为它将-copy发送给分配给它的任何内容。您的属性应使用retain属性而不是copy属性,初始化它的代码应如下所示:

NSMutableArray *localList = [[NSMutableArray alloc] init];
self.tableList = localList;
[localList release];

或者,更短的版本:

self.tableList = [NSMutableArray array];

在这种情况下无需复制任何内容,只需要创建一个新对象。

答案 2 :(得分:1)

如果你从另一个对象分配localList,那么在这种情况下它可能不是Mutable,它可以通过这种错误。

我希望它会有所帮助。

self.tableList = [localList mutableCopy];

答案 3 :(得分:0)

您好,而不是mutableCopy我相信“strong”也可以用来解决这个问题。我的代码中也存在类似的问题,因为使用“copy”代替“strong”。所以下面一行:

@property (copy, nonatomic) NSMutableArray *computers;

应该是:

@property (strong, nonatomic) NSMutableArray *computers;

希望这对初学者犯下像我这样的错误有很大的帮助。

答案 4 :(得分:0)

这将解决问题:

NSMutableArray *localList = [[NSMutableArray alloc] init];
self.localList = [[NSMutableArray alloc]initWithArray:localList];