7

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

* 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“* -[NSCFArray insertObject:atIndex:]: mutating method sent to immutable object”

这是数据控制器头文件: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

}

我非常感谢任何帮助。

提前感谢您的支持。

丹尼尔

4

5 回答 5

27

复制消息发送到 NSMutableArray(如init中的以下语句所示)会返回一个不可变副本。

self.tableList = [localList copy];

Cocoa 文档使用不可变一词来指代只读的、初始化后不能更改的对象。因此,对addObject:的后续调用失败并显示错误消息。

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

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

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

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

于 2009-08-03T22:40:04.203 回答
5

基本上,您遇到了 Cocoa 的内存管理规则(特别是这些细节)。如果存在具有不可变版本和可变版本的对象,则发送-copy到对象将返回不可变对象。

让我们逐步了解相关部分。

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

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

self.tableList = [localList copy];

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

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

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

这个属性是用copy属性声明的,所以每当一个新的值被分配给它时,另一个-copy方法被发送给它。然而,这第三个副本并不归您所有——它归对象所有。

[localList release];

这释放了原始的空可变数组。很好,但是你在第二行中制作的那个仍然漂浮在周围,未发布。那是内存泄漏。

如果您确实需要某个东西的可变副本,那么您需要该-mutableCopy方法。(这些方法的文档可以在NSCopying和下找到NSMutableCopying。)但是,您永远不会将某些东西的可变版本放入具有该属性的copy属性中,因为它将发送-copy到分配给它的任何东西。您的属性应该使用retain属性而不是copy属性,并且初始化它的代码应该如下所示:

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

或者,更短的版本:

self.tableList = [NSMutableArray array];

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

于 2009-08-03T23:55:24.910 回答
1

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

我希望它会有所帮助。

self.tableList = [localList mutableCopy];
于 2014-01-14T11:47:19.490 回答
0

这将解决问题:

NSMutableArray *localList = [[NSMutableArray alloc] init];
self.localList = [[NSMutableArray alloc]initWithArray:localList];
于 2014-11-18T08:14:23.193 回答
0

嗨,而不是 mutableCopy,我相信“ strong”也可以用来解决这个问题。copy由于使用“ ”而不是“ strong。” ,我的代码中也有类似的问题。所以下面一行:

@property (copy, nonatomic) NSMutableArray *computers;

它应该是:

@property (strong, nonatomic) NSMutableArray *computers;

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

于 2013-07-25T17:55:16.780 回答