在NSMutableString对象上调用stringWithString时崩溃

时间:2011-03-02 11:28:00

标签: iphone objective-c memory-management nsmutablestring

当用户点击“保存”按钮时,我运行了以下代码:

- (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.IsInGroupsBOOL数组,arrayGroups(NSString *) array,其中包含组名。 我想将newGroups字符串添加到arrayGroups[i] if (IsInGroups[i] == YES)

这段代码生成EXC_BAD_ACCESS。为什么?

感谢。

3 个答案:

答案 0 :(得分:2)

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

此行生成泄漏,然后是崩溃的原因。

执行此操作后,您不再拥有alloc / inited可变字符串的引用,并且您有一个自动释放的字符串。所以在该字符串上调用release会导致某个地方出现双重释放。

编辑:使用解决方案

最简单的解决方案:不要添加最后一个','。

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:@","];
    }
}

不是很优雅,但非常有效(尽管每次都可以避免计算)。

答案 1 :(得分:1)

在这里,您可以创建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相同] + smth more)。并将它分配给变量newGroups(因此存储在此变量中的旧值丢失)

  3. if([newGroups length]&gt; 0)     newGroups = [NSMutableString stringWithString:[newGroups substringToIndex:[newGroups length] - 1]];

    1. 这里的newGroups是自动释放的,你释放它,它就会破坏它。但由于它是自动释放的,自动释放池会尝试再次释放它并获得异常(因为内存已经全部免费)

      [newGroups release];

答案 2 :(得分:0)

你已经分配了一个字符串(NSMutableString * newGroups = [[NSMutableString alloc] init]; )

然后为其分配一个autorelease字符串(newGroups = [NSMutableString stringWithString:[newGroups substringToIndex:[newGroups length] - 1]]; )。

你永远不应该这样做。请参阅此博客 - http://andycodes.tumblr.com/post/947927280/difficult-bug-finally-solved

评论[newGroups release];并且代码应该可以正常工作。

同样总是设置NSZombieEnabled环境变量并再次运行代码,看一下崩溃日志,你会得到究竟是哪个对象导致崩溃。