iOS: NSASCIIStringEncoding doesn't encode certain characters correctly - ios

I have url that I am going to request data from. Here is the code.
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:
NSASCIIStringEncoding];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:urlStr]];
This works except when I have certain characters such as ş. The urlstr will return null. Is there a way around this to except certain character types? Any tips or suggestions are appreciated.

I've used the following method with success in many applications:
- (NSString *)urlEncode:(NSString *)str {
return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)str, NULL, CFSTR("!*'();:#&=+$,/?%#[]"), kCFStringEncodingUTF8));
}
Note that I use this on only the params of the URL, so the following would work (notice I added the ş, which seemed to work, although I'm not familiar with that character):
NSString *baseURL = #"http://www.google.com";
NSString *paramsString = #"testKey=test value_with some (weirdness)!___ş";
NSString *resultingURLString = [NSString stringWithFormat:#"%#?%#", baseURL, [self urlEncode:paramsString]];
Which produces the result:
http://www.google.com?testKey%3Dtest%20value_with%20some%20%28weirdness%29%21___%C5%9F

Related

NSURL returning nil

I dont know why but when I am calling the following URL
it gives me BAD REQUEST - INVALID URL, although this URL is working fine on safari browser and other browsers as well
http://www.ysl.com/wx/shop-product/women/top-handles#{"ytosQuery":"true","department":"handbags_tophandle_w","gender":"D","brand":"","macro":"","micro":"","season":"A,P,E","color":"","size":"","site":"","section":"","sortRule":"","yurirulename":"searchwithdepartment","microcolor":"","agerange":"","macroMarchio":"","page":"2","productsPerPage":"50","modelnames":"","look":"","washtype":"","fabric":"","prints":"","suggestion":"false","suggestionValue":"","material":"","occasion":"","weight":"","gal
I am using following code:
NSString *str = [NSString stringWithFormat:#"%#",[payload stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]];
NSString* webStringURL = [str stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
webStringURL = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *payload = [NSURL URLWithString:webStringURL];
Any Help Guys? What is that I am doing wrong?
Don't use stringByReplacingPercentEscapesUsingEncoding: on the hole URL, but just on the GET parameters.
Now http:// will also be escaped, thus becoming http%3A%2F%2F which is not valid as an URL.

Building an NSString based on a variadic number of arguments

My function takes a dictionary argument and a variadic number of NSString variables. All this combined is put in an [NSString stringWithFormat:] method, and is returned as a NSURLRequest. The method looks like this:
- (NSURLRequest *)buildPath:(NSString *)stringPath attributes:(NSString *)attribute, ...
{
va_list list;
NSString *eachObject;
NSMutableArray *args = [NSMutableArray array];
[args addObject:attribute];
va_start(list, attribute);
while ((eachObject = va_arg(list, NSString *))) {
[args addObject:eachObject];
}
va_end(list);
NSString *listOfAttributes = [args componentsJoinedByString:#", "];
NSString *pathURL = _requestString[stringPath];
NSString *path = [NSString stringWithFormat:pathURL, listOfAttributes];
NSURL *url = [NSURL URLWithString:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
return request;
}
This is what it looks like when I call the method:
NSURLRequest *request = [_venueService buildPath:#"categories"
attributes:_venueService.clientID, _venueService.clientSecret, _venueService.todaysDate, nil];
When I run the program, it crashes. When I log out listOfAttributes it gives me:
client_id, client_secret, 20140507
This is my 3 arguments, which is correct, and the stringPath (when I actually call it in my program I write stringPath[#"categories"]) which, when I NSLog gives me:
https://api.foursquare.com/v2/venues/categories?client_id=%#&client_secret=%#&v=%#
So, my question is, why would these two strings, combined in an [NSString stringWithFormat:] cause problems?
Any help would be greatly appreciated!
As Justin pointed out, there is a much simpler way of doing this. NSString has a -initWithFormat:arguments: method that does exactly what you want.
Also, your method name has a few issues:
Naming convention - you should indicate in the method name its purpose (creating a URL request)
You are passing in an (NSDictionary *) for the path, but casting it to an (NSString *) when you use it. The two objects are not type compatible. I'm supposing this might be a typo when you copy-pasted your code?
Might as well use the same calling convention as NSString's +stringWithFormat: method.
Given all of the above, the method becomes something like (without error checking):
- (NSURLRequest *)URLRequestWithFormat:(NSString *)format, ... {
va_list arguments;
va_start(arguments, format);
NSString *urlPath = [[NSString alloc] initWithFormat:format arguments:arguments];
va_end(arguments);
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
return request;
}
This worked fine with a call like:
NSURLRequest *request = [self URLRequestWithFormat:#"https://api.foursquare.com/v2/venues/categories/client_id=%#&client_secret=%#&v=%#", #"One",#"Two",#"Three"];
NSLog(#"Request: %#", request);
With output:
2014-05-07 09:52:30.645 Test[5888:60b] Request: <NSURLRequest: 0x8c64f30> { URL: https://api.foursquare.com/v2/venues/categories/client_id=One&client_secret=Two&v=Three }
You may want to read the documentation for -[NSString initWithFormat:arguments:]. That method accepts a va_list parameter and will probably do what you want.
The reason your sample code doesn't work is because stringWithFormat needs a separate argument for each placeholder that appears in the format string. Your format string looks like it contains three %# placeholders, but you're only passing one argument, listOfAttributes.
The format within stringPath is specifying that there should be 3 arguments, but you are only supplying one - listOfAttributes.
listOfAttributes is one argument not 3.

Creating NSURL with custom query parameter returns nil

I have a UISearchBar from which I'm extracting the text that represents an address and building from it a JSON URL for Google Geocoder.
NSString* address = searchbar.text;
NSString* url = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?address=%#&sensor=false", address];
If I copy & paste the url from debug window to the browser it works like a charm but when I try to convert it to NSURL i get nil
NSURL* theUrl = [NSURL URLWithString:url];
Any ideas?
I added the encoding to the address prior to concatenating the url and that fixed the problem so now the code looks like this:
NSString* address = searchbar.text;
NSString *encodedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, CFBridgingRetain(address), NULL, (CFStringRef)#"!*'();:#&=+$,/?%#[]", kCFStringEncodingUTF8));
NSString* url = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?address=%#&sensor=false", encodedString];

How to pass * () $ etc in NSUrl?

I tried to pass these characters to server, for example *()$
I have coded the NSUrl this way:
NSString *partialURL = [NSString stringWithFormat:#"/%#", commentBody];
NSString *fullURL = [NSString stringWithFormat:#"%#%#", CONST_URL, partialURL];
NSString *encStr = [fullURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:encStr];
But then, the commentBody passed in the url still has *()$ things and not encoded into utf8.
What is the correct way to do it?
Thanks!
NSString * test = (NSString *) CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)validUrl,
NULL,
(CFStringRef)#";/?:#&=$+{}<>,",
kCFStringEncodingUTF8);
UPDATE
Hi #Rendy. Sorry for the quickie reply yesterday. I only had time to past a 1-liner before jumping off and had hoped it would be enough for you to correct the issue you were having.
You always want to encode the parameters of the URL. IF you have a URL that is a parameter to another URL or embedded in some XML; you'll want to encode the entire url (which means parameters get double-encoded - because you take a "valid" URL and escape it so it becomes a valid parameter in another URL (ie, : and & get escaped, so parameters don't mix together.)
If you like, you can add additional chars to the string below and they'll be replaced with percent-encoded values. I believe the string below already has you covered for the invalid values.
Here's a category on NSString:
#implementation NSString (encode)
+ (NSString*)stringEncodedAsUrlParameter:(NSString *)string
{
NSString *newString = NSMakeCollectable(
[(NSString *)CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(CFStringRef)string,
NULL, /* charactersToLeaveUnescaped */
CFSTR(":/?#[]#!$ &'()*+,;=\"<>%{}|\\^~`"),
kCFStringEncodingUTF8
) autorelease]
);
if (newString) {
return newString;
}
return #"";
}
- (NSString*)stringByEncodingAsUrlParameter
{
return [NSString stringEncodedAsUrlParameter:self];
}
#end
Call it like this:
NSString * escapedParameters = [NSString stringEncodedAsUrlParameter:unescapedParameters];
Or:
NSString * escapedParameters = [unescapedParameters stringByEncodingAsUrlParameter];
Then add your properly escaped parameters to the end of your URL. If you encode the whole URL, you'll encode the "http://" portion and it won't work.
I originally copied the above from ASIHttpRequest, but any bugs added are mine.
Hope that helps! Best of luck!!

Data argument not used by format string but it works fine

I used this code from the Stack Overflow question: URLWithString: returns nil:
//localisationName is a arbitrary string here
NSString* webName = [localisationName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString* stringURL = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#,Montréal,Communauté-Urbaine-de-Montréal,Québec,Canadae&output=csv&oe=utf8&sensor=false", webName];
NSString* webStringURL = [stringURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL* url = [NSURL URLWithString:webStringURL];
When I copied it into my code, there wasn't any issue but when I modified it to use my url, I got this issue:
Data argument not used by format string.
But it works fine. In my project:
.h:
NSString *localisationName;
.m:
NSString* webName = [localisationName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString* stringURL = [NSString stringWithFormat:#"http://en.wikipedia.org/wiki/Hősök_tere", webName];
NSString* webStringURL = [stringURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL* url = [NSURL URLWithString:webStringURL];
[_webView loadRequest:[NSURLRequest requestWithURL:url]];
How can I solve this? Anything missing from my code?
The # in the original string is used as a placeholder where the value of webName is inserted. In your code, you have no such placeholder, so you are telling it to put webName into your string, but you aren't saying where.
If you don't want to insert webName into the string, then half your code is redundant. All you need is:
NSString* stringURL = #"http://en.wikipedia.org/wiki/Hősök_tere";
NSString* webStringURL = [stringURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL* url = [NSURL URLWithString:webStringURL];
[_webView loadRequest:[NSURLRequest requestWithURL:url]];
The +stringWithFormat: method will return a string created by using a given format string as a template into which the remaining argument values are substituted. And in the first code block, %# will be replaced by value of webName.
In your modified version, the format parameter, which is #"http://en.wikipedia.org/wiki/Hősök_tere", does not contain any format specifiers, so
NSString* stringURL = [NSString stringWithFormat:#"http://en.wikipedia.org/wiki/Hősök_tere", webName];
just runs like this (with the warning Data argument not used by format string.):
NSString* stringURL = #"http://en.wikipedia.org/wiki/Hősök_tere";

Resources