What is the best practic using url string with NSString stringWithFormat - ios

I use NSString stringWithFormat method for create an URL string. But now I have problem with a "quick" editing this string.
For example I have an script on the server that process some request with parameters.
I have an URL string like this:
http://www.domain.com/api/?param1=%#&param2=%#&param3=%#&param4=%#&param5=%#&
but when I have more than 5, 6 parameters it is really hard to modify this string.
Anybody knows best method how to create URL string (I mean when we modify it).

This is a sample of how to add parameters in a safe way. Long but reliable.
NSString* const kBaseURL = #"http://maps.google.com/maps/api/geocode/xml";
NSMutableDictionary *parameterDic = [NSMutableDictionary dictionary];
[parameterDic setObject:#"plaza de la puerta del sol 1, madrid, spain" forKey:#"address"];
[parameterDic setObject:#"false" forKey:#"sensor"];
NSMutableArray *parameters = [NSMutableArray array];
for (__strong NSString *name in parameterDic) {
NSString *value = [parameterDic objectForKey:name];
name = encodeToPercentEscapeString(name);
value = encodeToPercentEscapeString(value);
NSString *queryComponent = [NSString stringWithFormat:#"%#=%#", name, value];
[parameters addObject:queryComponent];
}
NSString *query = [parameters componentsJoinedByString:#"&"];
NSString *urlString = [NSString stringWithFormat:#"%#?%#", kBaseURL, query];
NSURL *url = [NSURL URLWithString:urlString];
NSLog(#"%#",url);
The code above calls this C function because stringByAddingPercentEscapesUsingEncoding won't convert some special characters in the name or value of the parameters. As pointed by Jesse Rusak see Proper URL (Percent) Encoding in iOS for a discussion.
// remove CFBridgingRelease and __bridge if your code is not ARC
NSString* encodeToPercentEscapeString(NSString *string) {
return (NSString *)
CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
(__bridge CFStringRef) string,
NULL,
(CFStringRef) #"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8));
}
This prints
http://maps.google.com/maps/api/geocode/xml?sensor=false&address=plaza%20de%20la%20puerta%20del%20sol%201,%20madrid,%20spain
Bonus track: how to deconstruct and rebuild a string:
NSString *stringUrl = #"http://www.google.com:80/a/b/c;params?m=n&o=p#fragment";
NSURL *url = [NSURL URLWithString:stringUrl];
NSLog(#"%#",stringUrl);
NSLog(#" scheme: %#",[url scheme]);
NSLog(#" host: %#",[url host]);
NSLog(#" port: %#",[url port]);
NSLog(#" path: %#",[url path]);
NSLog(#" relativePath: %#",[url relativePath]);
NSLog(#"parameterString: %#",[url parameterString]);
NSLog(#" query: %#",[url query]);
NSLog(#" fragment: %#",[url fragment]);
NSMutableString *s = [NSMutableString string];
[s appendFormat:#"%#://%#",[url scheme],[url host]];
if ([url port]!=nil){
[s appendFormat:#":%#",[url port]];
}
[s appendFormat:#"%#",[url path]];
if ([url parameterString]!=nil){
[s appendFormat:#";%#",[url parameterString]];
}
if ([url query]!=nil){
[s appendFormat:#"?%#",[url query]];
}
if ([url fragment]!=nil){
[s appendFormat:#"#%#",[url fragment]];
}
NSLog(#"%#",s);
This prints
http://www.google.com:80/a/b/c;params?m=n&o=p#fragment
scheme: http
host: www.google.com
port: 80
path: /a/b/c
relativePath: /a/b/c
parameterString: params
query: m=n&o=p
fragment: fragment

I wrote this specially for you, quite simple:
+ (NSString*) URlStringForBaseURL:(NSString*)baseURL withParams:(NSDictionary*)paramsdictonary{
NSString* url = [baseURL stringByAppendingString:#"?"];
NSUInteger index = 0;
for (NSString* key in [paramsdictonary allKeys]) {
index++;
if (index == [paramsdictonary count])
url = [url stringByAppendingFormat:#"%#=%#",key,[paramsdictonary valueForKey:key]];
else
url = [url stringByAppendingFormat:#"%#=%#&",key,[paramsdictonary valueForKey:key]];
}
return url;
}
And you can use it (of course, the order of the URL params is dos not matter):
NSMutableDictionary* params = [NSMutableDictionary dictionary];
[params setValue:#"value1" forKey:#"param1"];
[params setValue:#"value2" forKey:#"param2"];
[params setValue:#"value3" forKey:#"param3"];
NSString* urlStr = [HTMLTextFormat URlStringForBaseURL:#"http://www.domain.com/api/" withParams:params];
NSLog(#"url_: %#",urlStr);

Related

How to print the json data

I'm trying to learn JSON with IOS since I'm a beginner in IOS devices, i tried this code so far
-(void)retriveData
{
NSURL *url = [NSURL URLWithString:#"http://localhost/testjson.php"];
NSData *data = [NSData dataWithContentsOfURL:url];
json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
cities = [[NSMutableArray alloc] init];
for (int i=0; i<json.count; i++) {
NSString *cID = [[json objectAtIndex:i] objectForKey:#"id"];
NSString *cName = [[json objectAtIndex:i] objectForKey:#"CityName"];
NSString *cState = [[json objectAtIndex:i] objectForKey:#"CityState"];
NSString *cPopulation = [[json objectAtIndex:i] objectForKey:#"CityPopulation"];
NSString *cCountry = [[json objectAtIndex:i] objectForKey:#"Country"];
Country *myCity = [[Country alloc] initWithCityID:cID andCityName:cName andCityState:cState andCityPopulation:cPopulation andCityCountry:cCountry];
[cities addObject:myCity];
}
}
Anyone can show me now how i can print the data? this is the json file
[{"0":"1","id":"1","1":"Muscat","CityName":"Muscat","2":"Muscat","CityState":"Muscat","3":"25000","CityPopulation":"25000","4":"Oman","Country":"Oman"},{"0":"2","id":"2","1":"Bawsher","CityName":"Bawsher","2":"Muscat","CityState":"Muscat","3":"10000","CityPopulation":"10000","4":"Oman","Country":"Oman"},{"0":"3","id":"3","1":"AlMawalih","CityName":"AlMawalih","2":"Seeb","CityState":"Seeb","3":"5000","CityPopulation":"5000","4":"Oman","Country":"Oman"},{"0":"4","id":"4","1":"Oran","CityName":"Oran","2":"Oran","CityState":"Oran","3":"100000","CityPopulation":"100000","4":"Algeria","Country":"Algeria"},{"0":"5","id":"5","1":"Constantine","CityName":"Constantine","2":"Constantine","CityState":"Constantine","3":"150000","CityPopulation":"150000","4":"Algeria","Country":"Algeria"}]
Below is my very understandable and basic coding according to your question.It is helpful for you.
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://localhost/testjson.php"]];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json;charset=UTF-8" forHTTPHeaderField:#"content-type"];
NSError *err;
NSURLResponse *response;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
//You need to check response.Once you get the response copy that and paste in ONLINE JSON VIEWER in GOOGLE.If you do this clearly you can get the correct results.
//After that it depends upon the json format whether it is DICTIONARY or ARRAY
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:responseData options: NSJSONReadingMutableContainers error: &err];
NSLog(#"The json output array is - %#",jsonArray);
for(int i=0;i>[jsonArray count];i++)
{
NSString *strZero = [NSString stringWithFormat:#"%#",[array objectAtIndex:i]valueForKey:#"0"]];
NSLog(#"The zero is-%#",strZero);
NSString *strOne = [NSString stringWithFormat:#"%#",[array objectAtIndex:i]valueForKey:#"1"]];
NSLog(#"The One is-%#",strOne);
NSString *strTwo = [NSString stringWithFormat:#"%#",[array objectAtIndex:i]valueForKey:#"2"]];
NSLog(#"The Two is-%#",strTwo);
NSString *strThree = [NSString stringWithFormat:#"%#",[array objectAtIndex:i]valueForKey:#"3"]];
NSLog(#"The three is-%#",strThree);
NSString *strFour = [NSString stringWithFormat:#"%#",[array objectAtIndex:i]valueForKey:#"4"]];
NSLog(#"The four is-%#",strFour);
NSString *strID = [NSString stringWithFormat:#"%#",[array objectAtIndex:i]valueForKey:#"id"]];
NSLog(#"The ID is-%#",strID);
NSString *strCityName = [NSString stringWithFormat:#"%#",[array objectAtIndex:i]valueForKey:#"CityName"]];
NSLog(#"The CityName is-%#",strCityName);
NSString *strCityState = [NSString stringWithFormat:#"%#",[array objectAtIndex:i]valueForKey:#"CityState"]];
NSLog(#"The CityState is-%#",strCityState);
NSString *strCityPopulation = [NSString stringWithFormat:#"%#",[array objectAtIndex:i]valueForKey:#"CityPopulation"]];
NSLog(#"The CityPopulation is-%#",strCityPopulation);
NSString *strCountry = [NSString stringWithFormat:#"%#",[array objectAtIndex:i]valueForKey:#"Country"]];
NSLog(#"The Country is-%#",strCountry);
}
By printing you mean show the data in the console ?
Did you try this ?
NSString* str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Data: %#", str);

Cannot pass NSString to a NSURL URLWithString

Try to pass my NSString to a URLWithString but no url appear:
//here i get my url from my API and replacing tags
NSString *queryContent = [[[(webLinks)[#"content"] stringByReplacingOccurrencesOfString:#"&" withString:#"&"]
stringByReplacingOccurrencesOfString:#"<p>" withString:#""]
stringByReplacingOccurrencesOfString:#"</p>" withString:#""];
//here i get the full url
NSURL * url = [NSURL URLWithString:queryContent];
Adding a NSLogs:
NSLog(#"query:%#", queryContent);
NSLog(#"website:%#", url);
and the result is this:
query:http://mywebsite.com
website:(null)
Whats wrong?
thanks
//SOLVED//
here the correct code if any of you use my same system JSON API for WordPress:
NSRange r;
NSString *queryUrl = [(webLinks)[#"content"] stringByReplacingOccurrencesOfString:#"\n" withString:#""];
NSString *website = queryUrl;
while ((r = [website rangeOfString:#"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
website = [website stringByReplacingCharactersInRange:r withString:#""];
NSURL * url = [NSURL URLWithString:website];
[webView loadRequest:[NSURLRequest requestWithURL:url]];

Text File to NSArray

I have a text file that I download at launch from my website. It saves it to the Documents directory in the app. I want to read and process that text file and turn it into an NSArray.
I tried this:
- (NSArray *)articleReason {
NSString *filename3 = #"GameList.txt";
NSArray *pathArray3 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *documentsDirectory3 = [pathArray3 objectAtIndex:0];
NSString *yourSoundPath3 = [documentsDirectory3 stringByAppendingPathComponent:filename3];
NSURL *url = [NSURL fileURLWithPath:yourSoundPath3 isDirectory:NO];
NSString *urlData = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSArray *parsed = [urlData componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSIndexSet *indexes = [parsed indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
NSRange range = [(NSString *)obj rangeOfString:#"Reason:"];
if (range.location != NSNotFound)
{
return YES;
}
return NO;
}];
NSArray *disallowed = [parsed objectsAtIndexes:indexes];
NSString * myString = [disallowed componentsJoinedByString:#" "];
disallowed = [myString componentsSeparatedByString:#"Reason: "];
return disallowed;
}
This does not work. The thing is, if I download the text file while making the NSArray, it ends up working. Here's that code:
- (NSArray *)articleReason {
NSString *stringURL = kGameURL;
NSURL *url = [NSURL URLWithString:stringURL];
NSString *urlData = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSArray *parsed = [urlData componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
NSIndexSet *indexes = [parsed indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
NSRange range = [(NSString *)obj rangeOfString:#"Reason:"];
if (range.location != NSNotFound)
{
return YES;
}
return NO;
}];
NSArray *disallowed = [parsed objectsAtIndexes:indexes];
NSString * myString = [disallowed componentsJoinedByString:#" "];
disallowed = [myString componentsSeparatedByString:#"Reason: "];
return disallowed;
}
Any idea why this is not working? I verified in the Documents directory that the text file is downloading correctly. I do the downloading of the file in didFinishLaunching in the App Delegate. Here's that code:
NSString *stringURL2 = kGameURL;
NSURL *url2 = [NSURL URLWithString:stringURL2];
NSString *urlData2 = [NSString stringWithContentsOfURL:url2 encoding:NSUTF8StringEncoding error:nil];
NSFileManager *fileManager2 = [NSFileManager defaultManager];
NSString *docsDirectory2 = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path2 = [docsDirectory2 stringByAppendingPathComponent:#"GameList.txt"];
[urlData2 writeToFile:path2 atomically:YES ];
Any help would be greatly appreciated.
Figured it out.
[urlData2 writeToFile:path2 atomically:YES ];
Writeto file needed it include the encoding.

How to determine the file extension of a file from a URL (Objective-C)

I have a URL of type: http://example.com/files/
And I need to determine what file is there (extension and name of file). Depending on extensions, I'll do something.
How can I determine it?
Try
NSString *ext = [[url lastPathComponent] pathExtension];
See https://developer.apple.com/documentation/foundation/nsstring/1407801-pathextension
You can use this code directly just passing your NSUrl and get File Extension in return.
- (NSString *)findExtensionOfFileInUrl:(NSURL *)url{
NSString *urlString = [url absoluteString];
NSArray *componentsArray = [urlString componentsSeparatedByString:#"."];
NSString *fileExtension = [componentsArray lastObject];
return fileExtension;
}
Try This,
NSURL *urll = [NSURL URLWithString:#"http://example.com/files/firstFile.com"];
NSString *filenameWithExtension = [urll lastPathComponent];
NSRange *range = [filenameWithExtension rangeOfString:#"."];
USing the substringWithRange just substring of those ....
NSString *fileName = [string substringWithRange:NSMakeRange(0, range.location)];
NSString *extension = [string substringWithRange:NSMakeRange(10, string.length - range.location-1)];
NSLog(#"%# %#", fileName, extension);

How to extract and remove scheme name from NSURL?

What is proper way to extract and remove scheme name and :// from a NSURL?
For example:
note://Hello -> #"Hello"
calc://3+4/5 -> #"3+4/5"
so
NSString *scheme = #"note://";
NSString *path = #"Hello";
for later use in:
[[NSNotificationCenter defaultCenter] postNotificationName:scheme object:path];
You can look at it like this (mostly untested code, but you get the idea):
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
NSLog(#"url: %#", url);
NSLog(#"scheme: %#", [url scheme]);
NSLog(#"query: %#", [url query]);
NSLog(#"host: %#", [url host]);
NSLog(#"path: %#", [url path]);
NSDictionary * dict = [self parseQueryString:[url query]];
NSLog(#"query dict: %#", dict);
}
So you can do this:
NSString * strNoURLScheme =
[strMyURLWithScheme stringByReplacingOccurrencesOfString:[url scheme] withString:#""];
NSLog(#"URL without scheme: %#", strNoURLScheme);
parseQueryString
- (NSDictionary *)parseQueryString:(NSString *)query
{
NSMutableDictionary *dict = [[[NSMutableDictionary alloc] initWithCapacity:6] autorelease];
NSArray *pairs = [query componentsSeparatedByString:#"&"];
for (NSString *pair in pairs) {
NSArray *elements = [pair componentsSeparatedByString:#"="];
NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *val = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[dict setObject:val forKey:key];
}
return dict;
}
My inclination is to roll your own string searching for this:
NSRange dividerRange = [urlString rangeOfString:#"://"];
NSUInteger divide = NSMaxRange(dividerRange);
NSString *scheme = [urlString substringToIndex:divide];
NSString *path = [urlString substringFromIndex:divide];
This does what you've asked for in quite a literal fashion, dividing the URL in half around its scheme. For more advanced handling, you'll have to provide more details.
just use the NSURL's API named: resourceSpecifier :)
and remove the two slashes from the beginning of the string:
NSURL *url = [NSURL URLWithString:#"https://some.url.com/path];
url.resourceSpecifier will result in: //some.url.com/path
Remember, don't fight the frameworks especially when it comes to NSURL. This SO answer has a good breakdown of its abilities. https://stackoverflow.com/a/3693009/142358
NSURL's scheme and path properties are exactly what you want which (assuming the rest of your URL looks like a path) leaves you with this:
NSString *schemeWithDelimiter = [NSString stringWithFormat:#"%#://",[myURL scheme]];
[[NSNotificationCenter defaultCenter] postNotificationName: schemeWithDelimiter object:[myURL path];
No string searching needed!
Swift5, URL extension:
var resourceSpecifier: String {
get {
let nrl : NSURL = self as NSURL
return nrl.resourceSpecifier ?? self.absoluteString
}
}
var simpleSpecifier: String {
get {
let str = self.resourceSpecifier
return str[2..<str.count]
}
}

Resources