views:

43

answers:

3

How can I organize this string better for best coding practices. It's a string that defines filters:

NSString* string3 = [[[[[[tvA.text stringByReplacingOccurrencesOfString:@"\n" withString:@" "] stringByReplacingOccurrencesOfString:@"&" withString:@"and"] stringByReplacingOccurrencesOfString:@"garçon" withString:@"garcon"] stringByReplacingOccurrencesOfString:@"Garçon" withString:@"Garcon"] stringByReplacingOccurrencesOfString:@"+" withString:@"and"] stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];

Is there a way to have it be:

NSString* string3 = [[[[[tvA.text filter1] filter2] filter3] filter4] filter5] stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
+1  A: 

The first thing I'd do is capture the transformation into a method somewhere (where "somewhere" is either an instance method on an appropriate object or a class method on a utility class).

- (NSString *) transformString: (NSString *) aString
{
    NSString *transformedString;

    transformedString = [aString stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
    transformedString = [transformedString stringByReplacingOccurrencesOfString:@"&" withString:@"and"];
    transformedString = [transformedString stringByReplacingOccurrencesOfString:@"garçon" withString:@"garcon"];
    transformedString = [transformedString stringByReplacingOccurrencesOfString:@"Garçon" withString:@"Garcon"];
    transformedString = [transformedString stringByReplacingOccurrencesOfString:@"+" withString:@"and"];
    transformedString = [transformedString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];

    return transformedString;
}

Then:

NSString *result = [myTransformer transformString: tVA.text];

A bit brutish, but it'll work. And by "brutish", I mean that it is going to be slow and will cause a bunch of interim strings to pile up in the autorelease pool. However, if this is something that you only do every now and then, don't worry about it -- while brutish, it is certainly quite straightforward.

If, however, this shows up in performance analysis as a bottleneck, you could first move to using NSMutableString as it has methods for doing replacements in place. That, at least, will reduce memory thrash and will likely be a bit faster in that there is less copying of strings going on.

If that is still too slow, then you will likely need to write yourself a fun little bit of parsing and processing code that walks through the original and copies it to new a new string while also doing any necessary transforms along the way.

But, don't bother optimizing until you prove that it is a problem. And, of course, if it is a problem, you have just one method to optimize!

bbum
And if ever you *do* find yourself wanting/needing to transform the contents of a string on the fly, you might want to take a look at NSScanner: http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Strings/Articles/Scanners.html%23//apple_ref/doc/uid/20000147-BCIEFGHC
jlehr
You can mitigate problems with objects piling up in the autorelease pool by creating a new pool at the beginning of the method and draining it before returning.
Shaggy Frog
+1  A: 

If performance is not crucial, put the strings and their replacements into an NSDictionary and iterate over the items. Put it all in a helper method and use a NSMutableString to work on it (which reduces at least some of the cost).

Eiko
+1  A: 

You shouldn't be replacing & and + before percent-escaping. The problem is that stringByAddingPercentEscapesUsingEncoding: (IIRC) adds the minimum escapes to make it a "valid" URL string, whereas you want to escape anything that might have a special interpretation. For this, use CFURLCreateStringByAddingPercentEscapes():

return [(NSString*)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)aString, NULL, (CFStringRef)@":/?#[]@!$&'()*+,;=", kCFStringEncodingUTF8) autorelease];

This encodes & and + correctly, instead of just changing them to "and". It also encodes newlines as %0a (so you might want to replace them with spaces; that's your call), and encodes ç as %C3%A7 (which is decoded correctly if you use UTF-8 on the server).

tc.
hi tc - this works great, but it's crashing the app when any newlines are inputted. How can I make this work?
BigMike
I should say, when any 'returns' are inputted. This is inputting to the database perfectly, but when the app tries to load the data, it's crashing.
BigMike
How are you "loading" the data? What's the error message? Why are you "filtering" strings before putting them into the database? If it's a database on the phone, just use prepared statements.
tc.