3

Currently I have a string that I want to POST to a URL.

It works perfectly fine except when it encounters special characters like "&", and "?". It will not POST any data that comes after that. For example, if I have a string "I am something & something?", it will only POST "I am something". As for "?", it will be converted to '2' after it has been posted.

reason = 'What see see! Are you sure'2''

I am pretty sure that it must have something to do with encoding as I can see "I am something & something?" as it is just before I set the encoding:

NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding];

I have also tried the encodings below with no success:

NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding];
NSData *postData = [post dataUsingEncoding:NSNonLossyASCIIStringEncoding];
NSData *postData = [post dataUsingEncoding:NSISOLatin1StringEncoding];

Below are my codes from postData onwards:

NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding];
    //NSLog(@"PostData: %@", postData);
    NSString *check = [[NSString alloc] initWithData:postData encoding:NSASCIIStringEncoding];
    NSLog(@"check string = %@", check);
    NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:strURLQueryString]];
    [request setHTTPMethod:@"POST"];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    [request setHTTPBody:postData];
    NSURLResponse *response;
    NSError *err=nil;
    NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
    NSString *strResponse = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
     NSLog(@"Response: %@", strResponse);
     if(err!=nil) {
     NSLog(@"Error: %@", [err description]);
     }

Please assist. Your help(s) are appreciated.

Confused_person
  • 103
  • 1
  • 2
  • 11
  • So when you did `NSData *postData = [post dataUsingEncoding:SOME_ENCODING];` you followed it with `NSString *check = [[NSString alloc] initWithData:postData encoding:SOME_ENCODING]; NSLog(@"check string = %@", check);` and you were missing the characters at that time? – Carl Veazey Aug 15 '13 at 03:52
  • I never did that, but since you mentioned it, I tried it, and I could see the exact string. I will post subsequent codes. – Confused_person Aug 15 '13 at 03:59

1 Answers1

6

There's probably a better answer out there somewhere, but this class extension has been working for me for awhile. I cobbled together the % escapes by looking at a few posts...

//  NSString+URLEncoding.h
@interface NSString (NSString_URLEncoding)

- (NSString *)urlEncodeUsingEncoding:(CFStringEncoding)encoding;
- (NSString *)urlEncode;

@end

//  NSString+URLEncoding.m
@implementation NSString (NSString_URLEncoding)

- (NSString *)urlEncodeUsingEncoding:(CFStringEncoding)encoding {

    return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                     (__bridge CFStringRef)self,
                                                                     NULL,
                                                                     CFSTR("!*'();:@&=+$,/?%#[]"),
                                                                     encoding));
}

- (NSString *)urlEncode {

    return [self urlEncodeUsingEncoding:kCFStringEncodingUTF8];
}

Then in somer other class to send a string...

// SomeOtherClass.m

#import "NSString+URLEncoding.h"

NSString *encodedString = [@"This & this? are 'challenging' to !% encode" urlEncode];
danh
  • 62,181
  • 10
  • 95
  • 136
  • Here is what I did. 1. I created another class called "NSString+URLEncoding". 2. I declared your methods in .h and implemented the methods in .m. 3. Then I called the method, NSString *encodedReason = [reason urlEncode]; 4. In reference to 3, I get this error, No visible interface for NSMutableString declares the selector 'UrlEncode'. Am I missing something? – Confused_person Aug 15 '13 at 04:55
  • Have you imported the new created class `NSString+URLEncoding` where you are calling the `urlEncode` method? – Lucas Eduardo Aug 15 '13 at 05:01
  • @LucasEduardo Yes I had. – Confused_person Aug 15 '13 at 05:15
  • I tried editing to make more explicit how to do a class extension. This code definitely compiles and allows me to post percent encoded strings. – danh Aug 15 '13 at 05:55
  • Can I see your .h, .m file? Maybe I oversee a few things. – Confused_person Aug 15 '13 at 05:57
  • @danh By the way, I managed to remove the selector error. However, my app won't compile any more as I think the NSString extension perhaps interfere with the rest of the classes that I had, – Confused_person Aug 15 '13 at 06:00
  • Those are the complete .h and .m posted. Can you post the line where the compile error occurs? – danh Aug 15 '13 at 06:06
  • @danh Sorry. The reason it messes up all my other classes previously was because I did not include (NSString_URLEncoding). This is awesome! Now I can POST '&'. But I still cannot POST '?'. – Confused_person Aug 15 '13 at 07:05
  • Now I can POST almost everything, "Try & again. How about ''. What about %@#$^*(-=_+~", But not '?' yet. – Confused_person Aug 15 '13 at 07:15
  • I will open another question for "?". :) – Confused_person Aug 19 '13 at 03:46
  • Hmm. This encodes question marks. The one that delimits the query string should not be encoded. – danh Aug 19 '13 at 03:53
  • @danh: What do you mean? – Confused_person Aug 19 '13 at 04:29
  • For a get, the plain params might look like this: http://myservice.net/getsomething?foo="bar?" We want that to look like this: http://myservice.net/getsomething?foo=%22bar%3F%22. See how that question mark and equal sign are not encoded? They are url delimiters, but the "bar?" gets changed. I think the method I suggest will do this to the bar part, which is the right thing to do. – danh Aug 19 '13 at 04:39
  • Why do you think it does not do so for '?' ya? Attached is the ourput of checkString. subjective=UTF%208%20SUBJECTIVE.%20HEADER%20URLENDOCDED%20none%3F – Confused_person Aug 19 '13 at 04:47
  • Because you would avoid calling it to encode that delimiting question mark, just call it to encode the names and values. E.g. an encoded name value pair will look like this NSString *encodedPair = [NSString stringWithFormat@"%@=%@", [someName urlEncode], [someValue urlEncode]]; The whole URL will look like this NSString *urlString = [NSString stringWithFormat@"%@?%@", @"http://.../getsomething", encodedPair]; – danh Aug 19 '13 at 04:57
  • @danh If I understand you correctly, I did as what you suggested. You may want to check my new entry here at http://stackoverflow.com/questions/18306224/how-to-post-question-mark-to-a-web-service-objective-c where I show where did I call the urlEncode. – Confused_person Aug 19 '13 at 05:07
  • @danh How can I apply this to a dictionary because I have values in key pair for post request. – The iCoder Feb 10 '14 at 14:28
  • [NSString stringWithFormat:@"%@&%@", [key urlEncode], [d[key] urlEncode]); // where d is the dictionary and key is the key. You can do this in a loop using NSDictionary allKeys. – danh Feb 10 '14 at 16:30
  • Thanks this is great and I had to put `@end` at the end of .m part, and I have quit wondering how will the decode work? – Rakshitha Muranga Rodrigo May 23 '21 at 15:58
  • CFURLCreateStringByAddingPercentEscapes is deprecated. – Sabrina May 30 '22 at 15:11