Objective-c“发送到不可变对象的变异方法”错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1224040/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 22:00:57  来源:igfitidea点击:

objective-c "mutating method sent to immutable object" error

objective-cnsstringnsmutablearrayimmutability

提问by Oren Trutner

I'm pretty new to objective-c and try to create a small app for the iphone.
I'm nearly done beside this little error here. Actually, I've searched hours with google to find a proper solution but unfortunately I'm not able to find a solution which works.
I'm using this tutorial here to build up an UITableView: UITableView TutorialThe full error message looks like this:

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

* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '*-[NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'

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

This is the Data Controller Header: MyLinksDataController.h

这是数据控制器标题: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

.....

And the Data Controller Method: MyLinksDataController.m

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

}

-------------------------------later on in the source code---------------------------------

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

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

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

}

I would pretty much appreciate any help.

我非常感谢任何帮助。

Thank you for your support in advance.

提前感谢您的支持。

Daniel

丹尼尔

回答by Oren Trutner

Sending the copymessage to an NSMutableArray -- as in the following statement in init-- returns an immutable copy.

复制消息发送到 NSMutableArray —— 如下面的init语句—— 返回一个不可变的副本。

self.tableList = [localList copy];

Cocoa documentation uses the word immutableto refer to read-only, can't-be-changed-after-initialization objects. Hence the subsequenct call to addObject:fails with an error message.

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

Note how the assignment statement above doesn't trigger any compiler warning. copyreturns an id, which fits comfortably -- as far as the compiler is concerned -- in the NSMutableArray* tableList. There's no runtime error here either, as no messages get passed around; an NSArray pointer is just placed in an NSMutableArray pointer variable.

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

To obtain a mutable copy, use mutableCopyinstead.

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

Note that both copyand mutableCopycreate a new array and copy the content of the original to it. A change in the copy will not be reflected in the original. If you just need another reference to the original array, use retaininstead.

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

You can find more detail in the discussion section of the copyWithZone referenceand in the NSMutableCopying protocol reference.

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

回答by John Calsbeek

You're running into, basically, the memory management rules of Cocoa (specifically, these details). If there is an object with an immutable versionand a mutable version, then sending -copyto an object will return an immutable object.

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

Let's step through the relevant part.

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

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

This creates a new, empty mutable array that you own. Fine.

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

self.tableList = [localList copy];

This creates an immutablecopy of the empty array. Furthermore, you own this freshly created copy. That's two objects you own at the moment.

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

This also assigns your copied object to the tableListproperty. Let's look at the property declaration:

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

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

This property is declared with the copyattribute, so whenever a new value is assigned to it, another -copymethod is sent to it. This third copy, however, is not owned by you—it's owned by the object.

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

[localList release];

That releases the original empty mutable array. Fine, but there's still the one you made in the second line floating around, unreleased. That's a memory leak.

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

If you actually need a mutable copy of something, you want the -mutableCopymethod. (The documentation for these methods is found under NSCopyingand NSMutableCopying.) However, you're never going to get a mutable version of something into a property with the copyattribute, since it will send -copyto whatever it is assigned. Your property should use the retainattribute instead of the copyattribute, and the code to initialize it should look something like this:

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

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

Or, a shorter version:

或者,更短的版本:

self.tableList = [NSMutableArray array];

There's no need to copy anything in this situation, you're just creating a fresh object.

在这种情况下不需要复制任何东西,您只是在创建一个新对象。

回答by Gaurav

If u are assigning localList from another object may be that is not Mutable in that case it can through this kind of error.

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

I hope it will be helpful.

我希望它会有所帮助。

self.tableList = [localList mutableCopy];

回答by Asi Givati

This will resolve the issue:

这将解决问题:

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

回答by Rajeev Kumar Barnwal

Hi instead of mutableCopy i believe "strong" can also be used to tackle this problem. I had similar problem in my code as well because of using "copy" instead of "strong." So the below line:

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

@property (copy, nonatomic) NSMutableArray *computers;

It should be:

它应该是:

@property (strong, nonatomic) NSMutableArray *computers;

Hope it will be of immense help for beginners making mistakes like me.

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