Xcode - 连接大字符串时的EXC_BAD_ACCESS

时间:2010-05-04 16:06:06

标签: objective-c xcode nsstring nsmutablestring

在连接一个大字符串时,我得到一个EXEC_BAD_ACCESS。

我从Feed中读取并创建了我的webview,我建立了我的字符串,如:

NSString *pageData = @"<h1>header</h1>";

pageData = [pageData stringByAppendingFormat@"<p>"];
pageData = [pageData stringByAppendingFormat@"self.bodyText"];
pageData = [pageData stringByAppendingFormat@"</p>"];
etc

我得到的问题是self.bodytext是21,089个字符,当我对单词进行计数时有空格。 有没有更好的方法来做到这一点?

由于

4 个答案:

答案 0 :(得分:6)

您肯定希望将NSMutableString用于以下内容:

NSMutableString * pageData = [NSMutableString stringWithCapacity:0];

[pageData appendFormat:@"<h1>header</h1>"];
[pageData appendFormat:@"<p>"];
...

NSMutableString是为这种顺序连接而设计的,其中基本的NSString类实际上不是以这种方式使用的。每次调用stringByAppendFormat:时,您的原始代码实际上会分配一个新的NSString,然后继续将已经附加的所有数千个字符复制到其中。这可能很容易导致内存不足错误,因为随着您添加越来越多的调用,临时字符串的大小会呈指数级增长。

当您调用appendFormat:时,使用NSMutableString不会重新复制所有字符串数据,因为可变字符串维护一个内部缓冲区并简单地将新字符串添加到它的末尾。根据字符串的大小,您可能希望提前保留大量内存(对...WithCapacity:参数使用有意义的数字)。但除非你遇到性能问题,否则没有必要走这条路。

答案 1 :(得分:2)

您的示例代码存在一些问题:

  1. 您应该使用NSMutableString通过附加多个部分来构建输出字符串。 NSString是一个不可变类,这意味着每次调用stringByAppendingFormat:时,都会产生额外的新NSString对象的开销,需要由自动释放池收集和释放。

    NSMutableString * pageData = [NSMutableString stringWithCapacity:0];

  2. 您应该使用appendString:上的NSMutableString来附加内容,而不是stringByAppendingFormat:appendFormat:。格式方法用于基于格式说明符创建新字符串,格式说明符包含特殊字段作为占位符。有关详细信息,请参阅Formatting String Objects。当您使用stringByAppendingFormat:只有您的代码所具有的文字字符串时,您将承担为不存在的占位符解析字符串的开销,更重要的是,如果字符串碰巧有占位符(或者在其中看起来像一个东西的东西,你最终会得到你所得到的EXEC_BAD_ACCESS崩溃。很可能在附加了bodyText时会发生这种情况。因此,如果您只想在NSMutableString附加'

    ',请执行以下操作:

    [pageData appendString:@"<p>"];

  3. 如果要将self.bodyText属性的内容追加到字符串中,则不应将该属性的名称放在字符串文字内(即@“self.bodyText”是文字字符串“self.bodyText”,而不是属性的内容。尝试:

    [pageData appendString:self.bodyText];

  4. 例如,您可以使用格式规范实际组合示例代码的所有三行:

    pageData = [pageData stringByAppendingFormat:@"<p>%@</p>", self.bodyText];
    

    在格式规范中%@是一个占位符,表示插入向对象发送descriptiondescriptionWithLocale:消息的结果。对于NSString,这只是字符串的内容。

答案 2 :(得分:1)

我怀疑字符串的长度确实是个问题。 50,000个字符的字符串大约只有100 KB。但是你想要非常小心使用格式字符串。如果你的字符串包含看起来像格式化说明符的东西,那么最好有一个相应的参数,否则如果你运气好的话你会得到垃圾,如果不是你就会崩溃。我怀疑这是错误,因为您的描述中没有其他明显的问题。请注意放在那里的内容,并避免将动态文本放在格式字符串中 - 只需在格式字符串中放入%@并将动态文本作为参数传递。

答案 3 :(得分:1)

使用appendString:而不是appendFormat:处理任意字符串时。

pageData = [pageData stringByAppendingString:@"<p>"];
pageData = [pageData stringByAppendingString:@"self.bodyText"];
pageData = [pageData stringByAppendingString:@"</p>"];

或不要使用任意字符串作为格式:

pageData = [pageData stringByAppendingFormat:@"<p>%@</p>" , @"self.bodyText"];

如果要将字符串构建成碎片,请使用NSMutableString而不是几个stringBy调用。

请记住,%是格式化字符串和url转义的特殊字符,因此如果bodyText包含url,则很容易导致崩溃。