views:

276

answers:

4

I'm getting a EXEC_BAD_ACCESS when concatenting a large string.

I've read from a feed and to create my webview I build up my string like:

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

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

The problem I've got is self.bodytext is 21,089 characters with spaces when I do a count on word. Is there a better method for doing this?

Thanks

+6  A: 

You would definitely want to use NSMutableString for something like this:

NSMutableString * pageData = [NSMutableString stringWithCapacity:0];

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

NSMutableString is designed for this kind of sequential concatenation, where the basic NSString class is really not meant to be used in this manner. Your original code would actually allocate a new NSString every time you called stringByAppendFormat:, and then procede to copy into it all of the thousands of characters you had already appended. This could easily result in an out of memory error, since the size of the temporary strings would be growing exponentially as you add more and more calls.

Using NSMutableString will not re-copy all of the string data when you call appendFormat:, since the mutable string maintains an internal buffer and simply tacks new strings on to the end of it. Depending on the size of your string, you may want to reserve a huge chunk of memory ahead of time (use a meaningful number for the ...WithCapacity: argument). But there is no need to go that route unless you actually run into performance issues.

e.James
Since neither the example in the question, nor the sample code in the answer are actually using formats, you should probably use appendString: for NSMutableString ( see http://developer.apple.com/mac/library/documentation/cocoa/reference/Foundation/Classes/NSMutableString_Class/Reference/Reference.html#//apple_ref/doc/uid/20000156-appendString_) or stringByAppendingString: for NSString instances (see http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/stringByAppendingString:)
Jason Jenkins
@Jason Jenkins: Absolutely true. I stuck with the `appendFormat:` method because I *assume* that the OP will be inserting some dynamic data into the string eventually. Otherwise, he may as well type everything out in a text file and avoid the mutable string alltogether `:)`
e.James
What if the self.bodyText happened to include a substring that looked like a format specification (e.g. a '%@')? At runtime, with no arguments given, could that result in the EXEC_BAD_ACCESS the questioner is getting?
Jason Jenkins
Yes, it definitely could. I think you may be right about his intent for "self.bodyText" Why not post it as a separate answer?
e.James
+1  A: 

I doubt the length of the string is really a problem. A 50,000-character string is only about 100 KB. But you want to be very careful about using format strings. If your string contains something that looks like a formatting specifier, there had better be a corresponding argument or you'll get garbage if you're lucky and a crash if you're not. I suspect this is the error, since there is no other obvious problem from your description. Be careful about what you put in there, and avoid ever putting dynamic text in a format string — just put a %@ in the format string and pass the dynamic text as an argument.

Chuck
+1  A: 

Use appendString: instead of appendFormat: when dealing with arbitrary strings.

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

or do not use an arbitrary string as the format:

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

If you are building the string up in pieces, use NSMutableString instead of several stringBy calls.

Remember that % is a special character for formatted strings and for url escapes, so if bodyText contains a url it could easily cause a crash.

drawnonward
+2  A: 
Jason Jenkins
+1 very thorough.
e.James