我对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
}
我非常感谢任何帮助。
感谢您的支持。
丹尼尔
答案 0 :(得分:27)
将 copy 消息发送到NSMutableArray - 如 init 中的以下语句 - 返回不可变副本。
self.tableList = [localList copy];
Cocoa文档使用单词 immutable 来引用只读,不可更改的初始化对象。因此,对 addObject:的子序列调用失败并显示错误消息。
请注意上面的赋值语句不会触发任何编译器警告。 copy 返回一个 id ,就编译器而言,它非常适合NSMutableArray * tableList。这里也没有运行时错误,因为没有消息传递; NSArray指针只放在NSMutableArray指针变量中。
要获得可变副本,请改用 mutableCopy 。
请注意, copy 和 mutableCopy 都会创建一个新数组,并将原始内容复制到该数组中。副本中的更改不会反映在原件中。如果您只需要对原始数组的其他引用,请改为使用 retain 。
您可以在copyWithZone reference和NSMutableCopying 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
方法。 (这些方法的文档位于NSCopying
和NSMutableCopying
下。)但是,您永远不会在具有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];