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

7 objective-c immutability nsstring nsmutablearray

我对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

.....
Run Code Online (Sandbox Code Playgroud)

和数据控制器方法: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;

}
Run Code Online (Sandbox Code Playgroud)

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

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

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

}
Run Code Online (Sandbox Code Playgroud)

我非常感谢任何帮助.

感谢您的支持.

丹尼尔

Ore*_*ner 27

复制消息发送到NSMutableArray - 如在init中的以下语句中- 返回不可变副本.

self.tableList = [localList copy];
Run Code Online (Sandbox Code Playgroud)

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

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

要获取可变副本,请改用mutableCopy.

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

您可以在copyWithZone参考的讨论部分和NSMutableCopying协议参考中找到更多详细信息.


Joh*_*eek 5

基本上,你正在遇到Cocoa的内存管理规则(具体来说,这些细节).如果存在具有不可变版本和可变版本-copy的对象,则发送到对象将返回不可变对象.

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

NSMutableArray *localList = [[NSMutableArray alloc] init];
Run Code Online (Sandbox Code Playgroud)

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

self.tableList = [localList copy];
Run Code Online (Sandbox Code Playgroud)

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

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

@property (nonatomic, copy, readwrite) NSMutableArray *tableList;
Run Code Online (Sandbox Code Playgroud)

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

[localList release];
Run Code Online (Sandbox Code Playgroud)

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

如果你真的需要一个可变的东西副本,你想要的-mutableCopy方法.(这些方法的文档可以在NSCopyingNSMutableCopying.下找到.)但是,你永远不会将某个东西的可变版本带到属性的copy属性中,因为它会发送-copy给它所分配的任何东西.您的属性应该使用retain属性而不是copy属性,并且初始化它的代码应该如下所示:

NSMutableArray *localList = [[NSMutableArray alloc] init];
self.tableList = localList;
[localList release];
Run Code Online (Sandbox Code Playgroud)

或者,更短的版本:

self.tableList = [NSMutableArray array];
Run Code Online (Sandbox Code Playgroud)

在这种情况下没有必要复制任何东西,你只是创建一个新的对象.