target-c "Метод мутации отправлен в неизменяемый объект" Ошибка - PullRequest
7 голосов
/ 03 августа 2009

Я довольно новичок в объективе-c и пытаюсь создать небольшое приложение для iphone.
Я почти закончил с этой маленькой ошибкой здесь. На самом деле, я искал часы с Google, чтобы найти правильное решение, но, к сожалению, я не смог найти решение, которое работает.
Я использую это руководство здесь для создания UITableView: UITableView Tutorial Полное сообщение об ошибке выглядит так:

* Завершение работы приложения из-за необработанного исключения «NSInternalInconsistencyException», причина: «* - [NSCFArray insertObject: atIndex:]: метод мутации отправлен в неизменяемый объект»

Это заголовок контроллера данных: 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

}

Я бы очень признателен за любую помощь.

Заранее благодарим за поддержку.

Daniel

Ответы [ 5 ]

27 голосов
/ 04 августа 2009

Отправка сообщения copy в NSMutableArray - как в следующем выражении в init - возвращает неизменную копию.

self.tableList = [localList copy];

В документации по какао используется слово immutable для ссылки на объекты, доступные только для чтения и не подлежащие изменению после инициализации. Следовательно, последующий вызов addObject: завершается неудачно с сообщением об ошибке.

Обратите внимание, что оператор присваивания выше не вызывает никакого предупреждения компилятора. copy возвращает id , который удобно - с точки зрения компилятора - в NSMutableArray * tableList. Здесь также нет ошибки времени выполнения, так как сообщения не передаются; указатель NSArray только что помещен в переменную указателя NSMutableArray.

Чтобы получить изменяемую копию, используйте mutableCopy .

Обратите внимание, что copy и mutableCopy создают новый массив и копируют в него содержимое оригинала. Изменение в копии не будет отражено в оригинале. Если вам просто нужна другая ссылка на исходный массив, используйте retain .

Более подробную информацию можно найти в разделе обсуждения справки copyWithZone и справке NSMutableCopying .

5 голосов
/ 04 августа 2009

Вы сталкиваетесь, в основном, с правилами управления памятью Какао (в частности, , эти детали ). Если существует объект с неизменяемой версией и изменяемой версией, то отправка -copy объекту вернет неизменный объект.

Давайте пройдемся по соответствующей части.

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

Это создает новый пустой изменяемый массив, которым вы владеете. Хорошо.

self.tableList = [localList copy];

Это создает неизменную копию пустого массива. Кроме того, у вас есть эта недавно созданная копия. Это два объекта, которыми вы владеете в данный момент.

Это также присваивает ваш скопированный объект свойству tableList. Давайте посмотрим на объявление свойства:

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

Это свойство объявляется с атрибутом copy , поэтому, когда ему присваивается новое значение, ему отправляется другой метод -copy. Однако эта третья копия не принадлежит вам, она принадлежит объекту.

[localList release];

Это освобождает исходный пустой изменяемый массив. Хорошо, но есть еще тот, который вы сделали во второй строке, плавающий вокруг, неизданный. Это утечка памяти.

Если вам действительно нужна изменяемая копия чего-либо, вам нужен метод -mutableCopy. (Документация по этим методам находится в NSCopying и NSMutableCopying.) Однако вы никогда не получите изменяемую версию чего-либо в свойстве с помощью * Атрибут 1038 *, поскольку он будет отправлять -copy тому, кому он назначен. Ваше свойство должно использовать атрибут retain вместо атрибута copy, а код для его инициализации должен выглядеть примерно так:

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

Или, более короткая версия:

self.tableList = [NSMutableArray array];

В этой ситуации не нужно ничего копировать, вы просто создаете новый объект.

1 голос
/ 14 января 2014

Если вы присваиваете localList из другого объекта, возможно, что он не является изменяемым, в этом случае он может из-за такого рода ошибок.

Надеюсь, это будет полезно.

self.tableList = [localList mutableCopy];
0 голосов
/ 18 ноября 2014

Это решит проблему:

NSMutableArray *localList = [[NSMutableArray alloc] init];
self.localList = [[NSMutableArray alloc]initWithArray:localList];
0 голосов
/ 25 июля 2013

Привет вместо mutableCopy, я считаю, что "strong" также может быть использован для решения этой проблемы. У меня была похожая проблема в моем коде также из-за использования «copy» вместо «strong». Итак, строка ниже:

@property (copy, nonatomic) NSMutableArray *computers;

Должно быть:

@property (strong, nonatomic) NSMutableArray *computers;

Надеюсь, это будет огромной помощью для начинающих, совершающих ошибки, как я.

...