Online Book Reader

Home Category

iOS Recipes - Matt Drance [66]

By Root 274 0
as explained earlier. This is what ‑setFormParameters: does for us. An NSString category handles any necessary escaping.

BasicHTTPPost/PRPFormEncodedPOSTRequest.m

- (void)setFormParameters:(NSDictionary *)params {

NSStringEncoding enc = NSUTF8StringEncoding;

NSMutableString *postBody = [NSMutableString string];

for (NSString *paramKey in params) {

if ([paramKey length] > 0) {

NSString *value = [params objectForKey:paramKey];

NSString *encodedValue =

[value prp_URLEncodedFormStringUsingEncoding:enc];

NSUInteger length = [postBody length];

NSString *paramFormat = (length == 0 ? @"%@=%@" : @"&%@=%@");

[postBody appendFormat:paramFormat, paramKey, encodedValue];

}

}

NSLog(@"postBody is now %@", postBody);

[self setHTTPBody:[postBody dataUsingEncoding:enc]];

}

Simple, right? Actually, we need to do a bit more work to account for reserved characters.

The standard -[NSString stringByAddingPercentEscapesUsingEncoding:] method claims to “convert the receiver into a legal URL string.” This sounds promising, but we need more than that. What happens if the actual user input contains one of our reserved characters (+, &, =)? Nothing. These characters are technically “legal,” so NSString leaves them alone. However, a server might mistake a user-entered + for a space. Worse, user-entered ampersands will prematurely signal a new parameter. So although these characters are legal, they are not safe for our use. We need to escape them manually, and that’s where our category methods come in.

Our first category method, ‑prp_URLEncodedFormStringUsingEncoding:, is used by our request class to construct the HTTP body. It escapes the aforementioned reserved characters and then replaces each space with a plus (+). Order is important here: if we replace the spaces first, then our escape procedure will escape all of our pluses. We want only the user-entered pluses escaped, so we replace the spaces last.

BasicHTTPPost/NSString+PRPURLAdditions.m

- (NSString *)prp_URLEncodedFormStringUsingEncoding:(NSStringEncoding)enc {

NSString *escapedStringWithSpaces =

[self prp_percentEscapedStringWithEncoding:enc

additionalCharacters:@"&=+"

ignoredCharacters:nil];

return escapedStringWithSpaces;

}

The string conversion is done by our second category method, ‑prp_URLEncodedFormStringUsingEncoding:additionalCharacters:ignoredCharacters:. It takes two sets of characters: those that should be escaped (the reserved characters) and those that shouldn’t (the spaces—at least not right away). We’ve already determined that NSString can’t solve our problems, so we need to head down beneath Cocoa to its C counterpart, Core Foundation. A call to CFURLCreateStringByAddingPercentEscapes performs the specialized substitution we need, using our additionalCharacters and ignoredCharacters for custom behavior.

BasicHTTPPost/NSString+PRPURLAdditions.m

- (NSString *)prp_percentEscapedStringWithEncoding:(NSStringEncoding)enc

additionalCharacters:(NSString *)add

ignoredCharacters:(NSString *)ignore {

CFStringEncoding convertedEncoding =

CFStringConvertNSStringEncodingToEncoding(enc);

return [(NSString *)CFURLCreateStringByAddingPercentEscapes(

kCFAllocatorDefault,

(CFStringRef)self,

(CFStringRef)ignore,

(CFStringRef)add,

convertedEncoding)

autorelease];

}

Let’s review what’s going on here. The built-in behavior of Core Foundation (and thus Cocoa) is to escape only characters that are fundamentally illegal for use in URLs. Our POST use case, however, requires that some technically legal characters still be escaped. We accomplish that by passing &=+ for additionalCharacters.

Finally: a well-formed POST body string! Now we just get the data as UTF-8 (or whatever encoding your server requires) and set it as the request body. With the request in place, all we need to do now is create an NSURLConnection with our special request and submit it.

BasicHTTPPost/PRPURLEncodedPostViewController.m

NSURL *postURL = [NSURL URLWithString:URLString];

NSURLRequest *postRequest;

postRequest = [PRPFormEncodedPOSTRequest requestWithURL:postURL

formParameters:params];

Return Main Page Previous Page Next Page

®Online Book Reader