Сбой при вызове stringWithString для объекта NSMutableString - PullRequest
1 голос
/ 02 марта 2011

У меня работает следующий код, когда пользователь нажимает кнопку «Сохранить»:

- (IBAction) onSaveChangesClick:(id)sender  {

NSMutableString *newGroups = [[NSMutableString alloc] init];


for (int i = 0; i < [self.isInGroupArr count]; i++) {
    if ([[self.isInGroupArr objectAtIndex:i] boolValue] == YES) {
        [newGroups appendString:[[AppDelegate arrayGroups] objectAtIndex:i]];
        [newGroups appendString:@","];
    }
}

//  remove last : ","
if ([newGroups length] > 0)
    newGroups = [NSMutableString stringWithString:[newGroups substringToIndex:[newGroups length] - 1]];


self.contact.groups = newGroups;
[newGroups release];
//[[self navigationController] popViewControllerAnimated:YES];
}

self.IsInGroups - это массив BOOL, а arrayGroups - это (NSString *) array, который содержит имена групп.Я хотел бы добавить строку newGroups к arrayGroups[i] only if (IsInGroups[i] == YES).

Этот фрагмент кода генерирует EXC_BAD_ACCESS.ПОЧЕМУ?

Спасибо.

Ответы [ 3 ]

2 голосов
/ 02 марта 2011
newGroups = [NSMutableString stringWithString:[newGroups substringToIndex:[newGroups length] - 1]];

Эта строка генерирует утечку, а затем является причиной сбоя.

После того, как это выполнится, у вас больше нет ссылки на вашу изменяемую строку alloc / inited, и у вас есть автоматически освобожденная строка,Поэтому вызов release для этой строки вызывает двойное освобождение где-то.

EDIT: с решением

Самое простое решение: не добавлять последний ','.

for (int i = 0; i < [self.isInGroupArr count]; i++) {
    if ([[self.isInGroupArr objectAtIndex:i] boolValue] == YES) {
        [newGroups appendString:[[AppDelegate arrayGroups] objectAtIndex:i]];
        if (i != ([self.isInGroupArr count] - 1))
            [newGroups appendString:@","];
    }
}

Notочень элегантный, но довольно эффективный (хотя можно было бы избежать подсчета каждый раз).

1 голос
/ 02 марта 2011

Здесь вы создаете автоматически выпущенный экземпляр строки NSMutable.

newGroups = [NSMutableString stringWithString:[newGroups substringToIndex:[newGroups length] - 1]];

так что не стоит его выпускать, и все будет хорошо.

Вот улучшенный код:

- (IBAction) onSaveChangesClick:(id)sender  {

NSMutableString *newGroups = [[[NSMutableString alloc] init] autorelease];


for (int i = 0; i < [self.isInGroupArr count]; i++) {
    if ([[self.isInGroupArr objectAtIndex:i] boolValue] == YES) {
        [newGroups appendString:[[AppDelegate arrayGroups] objectAtIndex:i]];
        [newGroups appendString:@","];
    }
}

//  remove last : ","
if ([newGroups length] > 0)
    newGroups = [NSMutableString stringWithString:[newGroups substringToIndex:[newGroups length] - 1]];


self.contact.groups = newGroups;

//[[self navigationController] popViewControllerAnimated:YES];

}

Пояснение:

  1. Здесь вы выделяете память и сохраняете ее.

    [[NSMutableString alloc] init]

  2. [NSMutableString stringWithString: возвращает автоматически выпущенный экземпляр строки NSMutable, который мы не должны выпускать (он делает то же самое, что [[[NSMutableString alloc] init] autorelease] + что-то еще). и вы назначаете его переменной newGroups (поэтому ваше старое значение, которое хранилось в этой переменной, потеряно)

if ([длина новой группы]> 0) newGroups = [NSMutableString stringWithString: [newGroups substringToIndex: [длина новой группы] - 1]];

  1. newGroups здесь автоматически выпущен, вы отпускаете его, и он уничтожает. Но так как он был автоматически освобожден, пул автозапуска пытается освободить его снова и получает исключение (поскольку память уже свободна)

    [выпуск новой группы];

0 голосов
/ 02 марта 2011

Вы выделили строку (NSMutableString * newGroups = [[NSMutableString alloc] init];)

и затем присвоили ей строку автоматического выпуска (newGroups = [NSMutableString stringWithString: [newGroups substringToIndex: [newGroups length] - 1]];).

Что вы никогда не должны делать.Посмотрите этот блог - http://andycodes.tumblr.com/post/947927280/difficult-bug-finally-solved

Прокомментируйте [выпуск новой группы];и код должен работать нормально.

Также всегда устанавливайте переменную окружения NSZombieEnabled и снова запускайте код, просматривайте журнал сбоя, вы получите точно, какой объект вызывает сбой.

...