I am fresher to iOS, i am getting problem at checking string object contains URL or string?
NSMutableArray *Arr=[NSMutableArray alloc]initWithObject:#"Welcome", #"http://abcd.com/Images/bus.png", nil];
int i;
i++;
NSString *str=[Arr objectAtIndex:i];
Now, i want to check condition, if string contains "Welcome", have to display on label or if it is URL , i need to display that URL image in ImageView. So how can i check it? Please help me in this problem.
Instead of initiating both as NSStrings, try differentiating between them by making urls a NSURL (special container specifically for urls):
NSMutableArray* Arr = [NSMutableArray alloc]initWithObject:#"Welcome", [NSURL URLWithString:#"http://abcd.com/Images/bus.png"], nil];
for(id object in Arr)
{
if([object isKindOfClass:[NSString class]])
{
NSString* string = object;
NSLog(#"String: %#", string);
}
else if([object isKindOfClass:[NSURL class]])
{
NSURL* url = object;
NSLog(#"URL: %#", url);
}
}
Try like this
NSMutableArray *Arr=[[NSMutableArray alloc]initWithObjects:#"Welcome", #"http://abcd.com/Images/bus.png",nil];
NSString *st=nil;
for(NSString *string in Arr)
{
NSArray *matches = [detector
matchesInString:string
options:0
range:NSMakeRange(0,
[string length])];
for (NSTextCheckingResult *match in
matches) {
if ([match resultType] ==
NSTextCheckingTypeLink) {
NSURL *url = [match URL];
} else
{
NSlog(#"it is a string");
}
}
}
Try this, it will help you:
NSMutableArray *Arr=[[NSMutableArray alloc]initWithObjects:#"Welcome", #"http://abcd.com/Images/bus.png", nil];
if([Arr count])
{
for (NSString *str in Arr)
{
if([str isEqualToString:#"Welcome"])
{
NSLog(#"str is %#",str);
//do whatever you want
}
if([str isEqualToString:#"http://abcd.com/Images/bus.png"])
{
NSLog(#"str is %#",str);
//do whatever you want
}
}
}
To check NSString is containing a URL You can Try This code
if ([stringName hasPrefix:#"http://"] || [stringName hasPrefix:#"https://"]) {
//show imageVivew
}
Related
This code had been working fine until just recently. I hadn't' changed anything nor upgraded my system and I'm completely flummoxed.
I've been using it for 6 years and now it dies on me.
Is there an easier or better way of running an applescript from within a cocoa application? At this point I'm happy to pay to fix this problem!
utils.h
#import <Foundation/Foundation.h>
#interface Utils : NSObject
// Runs an applescript with a given map of variables (name/value)
+ (NSArray *)runApplescript:(NSString *)source withVariables:(NSDictionary *)variables;
// Runs an applescript from a file pathwith a given map of variables
// (name/value)
+ (NSArray *)runApplescriptFromFile:(NSString *)scriptName withVariables:(NSDictionary *)variables;
+ (NSArray *)arrayFromDescriptor:(NSAppleEventDescriptor *)descriptor;
// String is empty or only has white characters (space, tab...)
+ (BOOL)stringIsEmptyOrWhite:(NSString *)string;
#end
Utils.M
#import "Utils.h"
#implementation Utils
+ (NSArray *)arrayFromDescriptor:(NSAppleEventDescriptor *)descriptor {
// Enumerate the apple descriptors (lists) returned by the applescript and
// make them into arrays
NSMutableArray *returnArray = [NSMutableArray array];
NSInteger counter, count = [descriptor numberOfItems];
for (counter = 1; counter <= count; counter++) {
NSAppleEventDescriptor *desc = [descriptor descriptorAtIndex:counter];
if (nil != [desc descriptorAtIndex:1]) {
[returnArray addObject:[Utils arrayFromDescriptor:desc]];
} else {
NSString *stringValue = [[descriptor descriptorAtIndex:counter] stringValue];
if (nil != stringValue) {
[returnArray addObject:stringValue];
} else {
[returnArray addObject:#""];
}
}
}
return returnArray;
}
+ (NSString *)escapeCharacters:(NSString *)string {
return [string stringByReplacingOccurrencesOfString:#"\"" withString:#"\\\""];
}
+ (NSArray *)runApplescript:(NSString *)source withVariables:(NSDictionary *)variables {
NSString *input = #"";
NSArray *variableNames = [variables allKeys];
// Transform the dictionary of names/values to set sentences of applescript
for (NSString *variableName in variableNames) {
NSObject *variableValue = [variables objectForKey:variableName];
if ([variableValue isKindOfClass:[NSString class]]) {
input =
[input stringByAppendingString:[NSString stringWithFormat:#"set %# to (\"%#\" as text)\n", variableName,
[Utils escapeCharacters:variableValue], nil]];
} else if ([variableValue isKindOfClass:[NSNumber class]]) {
input = [input stringByAppendingString:[NSString stringWithFormat:#"set %# to (%# as integer)\n",
variableName, variableValue, nil]];
} else if ([variableValue isKindOfClass:[NSArray class]]) {
// Initialize a list
NSString *entry;
NSArray *values = (NSArray *)variableValue;
input = [input stringByAppendingString:[NSString stringWithFormat:#"set %# to {", variableName]];
BOOL first = TRUE;
for (entry in values) {
if (!first) {
input = [input stringByAppendingString:#", "];
}
input = [input
stringByAppendingString:[NSString stringWithFormat:#"\"%#\"", [Utils escapeCharacters:entry], nil]];
first = FALSE;
}
input = [input stringByAppendingString:#"}\n"];
}
}
NSString *finalScript = [input stringByAppendingString:[NSString stringWithFormat:#"\n\n%#", source]];
NSLog(#"Final script: %#", finalScript);
NSAppleScript *script = [[NSAppleScript alloc] initWithSource:finalScript];
NSDictionary *error;
NSAppleEventDescriptor *descriptor = [script executeAndReturnError:&error];
NSLog(#"applescript error: %#", [error description]);
// Transform the return value of applescript to nested nsarrays
return [Utils arrayFromDescriptor:descriptor];
}
+ (NSArray *)runApplescriptFromFile:(NSString *)scriptName withVariables:(NSDictionary *)variables {
NSString *scriptPath = [[NSBundle mainBundle] pathForResource:scriptName ofType:#"applescript"];
NSString *scriptSource =
[[NSString alloc] initWithContentsOfFile:scriptPath encoding:NSASCIIStringEncoding error:nil];
return [Utils runApplescript:scriptSource withVariables:variables];
}
+ (BOOL)stringIsEmptyOrWhite:(NSString *)string {
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [string isEqualToString:#""];
}
#end
Easier, yes, although whether that’s your actual problem is another question.
http://appscript.sourceforge.net/asoc.html
I assume you’ve already got other details, including sandboxing and hardening settings and plist entries, taken care of. (Recent Xcode upgrades also had a habit of breaking it when auto-upgrading your project files, by turning on hardening for you so Apple events can’t get out.)
I want to test some cases in my app with strings which have the same hash, and I can't find it =(
I've found two strings with the same MD5. here But their hash are different. And googling didn't help me =(
NSString(MD5) category
Little story about NSDictionary
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSString *string1 = [self fileContentWithName:#"message1" encoding:NSUnicodeStringEncoding];
NSString *string2 = [self fileContentWithName:#"message2" encoding:NSUnicodeStringEncoding];
if (string1 != nil) {
if (string1.hash == string2.hash) {
NSLog(#"Hashes are the same");
} else {
if ([[string1 MD5Hash] isEqualToString:[string2 MD5Hash]]) {
NSLog(#"MD5 hases are equalfor:");
NSLog(#"lenght = %3ld - %#", string1.length, string1);
NSLog(#"lenght = %3ld - %#", string2.length, string2);
if ([string1 isEqualToString:string2]) {
NSLog(#"Strings are equal too");
} else {
NSLog(#"But strings are not equal");
}
}
}
}
}
#pragma mark -
- (NSString*)fileContentWithName:(NSString*)name encoding:(NSStringEncoding)enc
{
NSString *txtFilePath1 = [[NSBundle mainBundle] pathForResource:name ofType:#"bin"];
NSError *error = nil;
NSString *txtFileContents1 = [NSString stringWithContentsOfFile:txtFilePath1 encoding:enc error:&error];
return txtFileContents1;
}
With all the URL-handling objects lying around in the standard Cocoa libraries (NSURL, NSMutableURL, NSMutableURLRequest, etc), I know I must be overlooking an easy way to programmatically compose a GET request.
Currently I'm manually appending "?" followed by name value pairs joined by "&", but all of my name and value pairs need to be manually encoded so NSMutableURLRequest doesn't fail entirely when it tries to connect to the URL.
This feels like something I should be able to use a pre-baked API for.... is there anything out of the box to append an NSDictionary of query parameters to an NSURL? Is there another way I should approach this?
Introduced in iOS8 and OS X 10.10 is NSURLQueryItem, which can be used to build queries. From the docs on NSURLQueryItem:
An NSURLQueryItem object represents a single name/value pair for an item in the query portion of a URL. You use query items with the queryItems property of an NSURLComponents object.
To create one use the designated initializer queryItemWithName:value: and then add them to NSURLComponents to generate an NSURL. For example:
NSURLComponents *components = [NSURLComponents componentsWithString:#"http://stackoverflow.com"];
NSURLQueryItem *search = [NSURLQueryItem queryItemWithName:#"q" value:#"ios"];
NSURLQueryItem *count = [NSURLQueryItem queryItemWithName:#"count" value:#"10"];
components.queryItems = #[ search, count ];
NSURL *url = components.URL; // http://stackoverflow.com?q=ios&count=10
Notice that the question mark and ampersand are automatically handled. Creating an NSURL from a dictionary of parameters is as simple as:
NSDictionary *queryDictionary = #{ #"q": #"ios", #"count": #"10" };
NSMutableArray *queryItems = [NSMutableArray array];
for (NSString *key in queryDictionary) {
[queryItems addObject:[NSURLQueryItem queryItemWithName:key value:queryDictionary[key]]];
}
components.queryItems = queryItems;
I've also written a blog post on how to build URLs with NSURLComponents and NSURLQueryItems.
You can create a category for NSDictionary to do this -- there isn't a standard way in the Cocoa library that I could find either. The code that I use looks like this:
// file "NSDictionary+UrlEncoding.h"
#import <cocoa/cocoa.h>
#interface NSDictionary (UrlEncoding)
-(NSString*) urlEncodedString;
#end
with this implementation:
// file "NSDictionary+UrlEncoding.m"
#import "NSDictionary+UrlEncoding.h"
// helper function: get the string form of any object
static NSString *toString(id object) {
return [NSString stringWithFormat: #"%#", object];
}
// helper function: get the url encoded string form of any object
static NSString *urlEncode(id object) {
NSString *string = toString(object);
return [string stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
}
#implementation NSDictionary (UrlEncoding)
-(NSString*) urlEncodedString {
NSMutableArray *parts = [NSMutableArray array];
for (id key in self) {
id value = [self objectForKey: key];
NSString *part = [NSString stringWithFormat: #"%#=%#", urlEncode(key), urlEncode(value)];
[parts addObject: part];
}
return [parts componentsJoinedByString: #"&"];
}
#end
I think the code's pretty straightforward, but I discuss it in some more detail at http://blog.ablepear.com/2008/12/urlencoding-category-for-nsdictionary.html.
I wanted to use Chris's answer, but it wasn't written for Automatic Reference Counting (ARC) so I updated it. I thought I'd paste my solution in case anyone else has this same issue. Note: replace self with the instance or class name where appropriate.
+(NSString*)urlEscapeString:(NSString *)unencodedString
{
CFStringRef originalStringRef = (__bridge_retained CFStringRef)unencodedString;
NSString *s = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,originalStringRef, NULL, (CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ", kCFStringEncodingUTF8);
CFRelease(originalStringRef);
return s;
}
+(NSString*)addQueryStringToUrlString:(NSString *)urlString withDictionary:(NSDictionary *)dictionary
{
NSMutableString *urlWithQuerystring = [[NSMutableString alloc] initWithString:urlString];
for (id key in dictionary) {
NSString *keyString = [key description];
NSString *valueString = [[dictionary objectForKey:key] description];
if ([urlWithQuerystring rangeOfString:#"?"].location == NSNotFound) {
[urlWithQuerystring appendFormat:#"?%#=%#", [self urlEscapeString:keyString], [self urlEscapeString:valueString]];
} else {
[urlWithQuerystring appendFormat:#"&%#=%#", [self urlEscapeString:keyString], [self urlEscapeString:valueString]];
}
}
return urlWithQuerystring;
}
The other answers work great if the values are strings, however if the values are dictionaries or arrays then this code will handle that.
Its important to note that there is no standard way of passing an array/dictionary via the query string but PHP handles this output just fine
-(NSString *)serializeParams:(NSDictionary *)params {
/*
Convert an NSDictionary to a query string
*/
NSMutableArray* pairs = [NSMutableArray array];
for (NSString* key in [params keyEnumerator]) {
id value = [params objectForKey:key];
if ([value isKindOfClass:[NSDictionary class]]) {
for (NSString *subKey in value) {
NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)[value objectForKey:subKey],
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
[pairs addObject:[NSString stringWithFormat:#"%#[%#]=%#", key, subKey, escaped_value]];
}
} else if ([value isKindOfClass:[NSArray class]]) {
for (NSString *subValue in value) {
NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)subValue,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
[pairs addObject:[NSString stringWithFormat:#"%#[]=%#", key, escaped_value]];
}
} else {
NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)[params objectForKey:key],
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
[pairs addObject:[NSString stringWithFormat:#"%#=%#", key, escaped_value]];
[escaped_value release];
}
}
return [pairs componentsJoinedByString:#"&"];
}
Examples
[foo] => bar
[translations] =>
{
[one] => uno
[two] => dos
[three] => tres
}
foo=bar&translations[one]=uno&translations[two]=dos&translations[three]=tres
[foo] => bar
[translations] =>
{
uno
dos
tres
}
foo=bar&translations[]=uno&translations[]=dos&translations[]=tres
I refactored and converted to ARC answer by AlBeebe
- (NSString *)serializeParams:(NSDictionary *)params {
NSMutableArray *pairs = NSMutableArray.array;
for (NSString *key in params.keyEnumerator) {
id value = params[key];
if ([value isKindOfClass:[NSDictionary class]])
for (NSString *subKey in value)
[pairs addObject:[NSString stringWithFormat:#"%#[%#]=%#", key, subKey, [self escapeValueForURLParameter:[value objectForKey:subKey]]]];
else if ([value isKindOfClass:[NSArray class]])
for (NSString *subValue in value)
[pairs addObject:[NSString stringWithFormat:#"%#[]=%#", key, [self escapeValueForURLParameter:subValue]]];
else
[pairs addObject:[NSString stringWithFormat:#"%#=%#", key, [self escapeValueForURLParameter:value]]];
}
return [pairs componentsJoinedByString:#"&"];
}
- (NSString *)escapeValueForURLParameter:(NSString *)valueToEscape {
return (__bridge_transfer NSString *) CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef) valueToEscape,
NULL, (CFStringRef) #"!*'();:#&=+$,/?%#[]", kCFStringEncodingUTF8);
}
If you are already using AFNetworking (as was the case with me), you can use it's class AFHTTPRequestSerializer to create the required NSURLRequest.
[[AFHTTPRequestSerializer serializer] requestWithMethod:#"GET" URLString:#"YOUR_URL" parameters:#{PARAMS} error:nil];
In case you only require the URL for your work, use NSURLRequest.URL.
Here is a simple example in Swift (iOS8+):
private let kSNStockInfoFetchRequestPath: String = "http://dev.markitondemand.com/Api/v2/Quote/json"
private func SNStockInfoFetchRequestURL(symbol:String) -> NSURL? {
if let components = NSURLComponents(string:kSNStockInfoFetchRequestPath) {
components.queryItems = [NSURLQueryItem(name:"symbol", value:symbol)]
return components.URL
}
return nil
}
I took Joel's recommendation of using URLQueryItems and turned into a Swift Extension (Swift 3)
extension URL
{
/// Creates an NSURL with url-encoded parameters.
init?(string : String, parameters : [String : String])
{
guard var components = URLComponents(string: string) else { return nil }
components.queryItems = parameters.map { return URLQueryItem(name: $0, value: $1) }
guard let url = components.url else { return nil }
// Kinda redundant, but we need to call init.
self.init(string: url.absoluteString)
}
}
(The self.init method is kinda cheesy, but there was no NSURL init with components)
Can be used as
URL(string: "http://www.google.com/", parameters: ["q" : "search me"])
I've got another solution:
http://splinter.com.au/build-a-url-query-string-in-obj-c-from-a-dict
+(NSString*)urlEscape:(NSString *)unencodedString {
NSString *s = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ",
kCFStringEncodingUTF8);
return [s autorelease]; // Due to the 'create rule' we own the above and must autorelease it
}
// Put a query string onto the end of a url
+(NSString*)addQueryStringToUrl:(NSString *)url params:(NSDictionary *)params {
NSMutableString *urlWithQuerystring = [[[NSMutableString alloc] initWithString:url] autorelease];
// Convert the params into a query string
if (params) {
for(id key in params) {
NSString *sKey = [key description];
NSString *sVal = [[params objectForKey:key] description];
// Do we need to add ?k=v or &k=v ?
if ([urlWithQuerystring rangeOfString:#"?"].location==NSNotFound) {
[urlWithQuerystring appendFormat:#"?%#=%#", [Http urlEscape:sKey], [Http urlEscape:sVal]];
} else {
[urlWithQuerystring appendFormat:#"&%#=%#", [Http urlEscape:sKey], [Http urlEscape:sVal]];
}
}
}
return urlWithQuerystring;
}
You can then use it like so:
NSDictionary *params = #{#"username":#"jim", #"password":#"abc123"};
NSString *urlWithQuerystring = [self addQueryStringToUrl:#"https://myapp.com/login" params:params];
-(NSString*)encodeDictionary:(NSDictionary*)dictionary{
NSMutableString *bodyData = [[NSMutableString alloc]init];
int i = 0;
for (NSString *key in dictionary.allKeys) {
i++;
[bodyData appendFormat:#"%#=",key];
NSString *value = [dictionary valueForKey:key];
NSString *newString = [value stringByReplacingOccurrencesOfString:#" " withString:#"+"];
[bodyData appendString:newString];
if (i < dictionary.allKeys.count) {
[bodyData appendString:#"&"];
}
}
return bodyData;
}
Yet another solution, if you use RestKit there's a function in RKURLEncodedSerialization called RKURLEncodedStringFromDictionaryWithEncoding that does exactly what you want.
Simple way of converting NSDictionary to url query string in Objective-c
Ex: first_name=Steve&middle_name=Gates&last_name=Jobs&address=Palo Alto, California
NSDictionary *sampleDictionary = #{#"first_name" : #"Steve",
#"middle_name" : #"Gates",
#"last_name" : #"Jobs",
#"address" : #"Palo Alto, California"};
NSMutableString *resultString = [NSMutableString string];
for (NSString* key in [sampleDictionary allKeys]){
if ([resultString length]>0)
[resultString appendString:#"&"];
[resultString appendFormat:#"%#=%#", key, [sampleDictionary objectForKey:key]];
}
NSLog(#"QueryString: %#", resultString);
Hope will help :)
If you are already using AFNetwork, you can use their built in serializer to to produce an encoded URL;
NSString *baseURL = #"https://api.app.com/parse";
NSDictionary *mutableParameters = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"true",#"option1", data, #"option2", token, #"token", #"3.0", #"app", nil];
NSURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"GET" URLString:baseURL parameters:mutableParameters error:nil];
NSString *urlPath = request.URL.absoluteString;
NSLog(#"%#", urlPath); // https://api.app.com/parse?option1=true&option2=datavalue&token=200%3ATEST%3AENCODE ....
Note; this is an extension to an above answer. The edit queue is full so cannot be added to the existing answer.
I know this can be faster but i dont have years of experience in coding so i am just learning the hard way..
I made a function that checks if a string is not "" if not add it to a nsurl and then i check if the nsurl is not nil and add it to a mutable array:
-(void)CheckUrls
{
self.items = [NSMutableArray array];
NSURL *URL1 ;
NSURL *URL2 ;
NSURL *URL3 ;
NSURL *URL4 ;
NSURL *URL5 ;
NSURL *URL6 ;
NSLog(#" FOTO 1: %# \n FOTO2 : %# \n FOTO 3 : %# \n FOTO 4 : %# \n FOTO 5: %# \n FOTO 6: %# \n",self.searchResult.foto1,self.searchResult.foto2,self.searchResult.foto3,self.searchResult.foto4,self.searchResult.foto5,self.searchResult.foto6);
if (![self.searchResult.foto1 isEqualToString:#""]) {
URL1 = [NSURL URLWithString:self.searchResult.foto1];
}
if (![self.searchResult.foto2 isEqualToString:#""]) {
URL2 = [NSURL URLWithString:self.searchResult.foto2];
}
if (![self.searchResult.foto3 isEqualToString:#""]) {
URL3 = [NSURL URLWithString:self.searchResult.foto3];
}
if (![self.searchResult.foto4 isEqualToString:#""]) {
URL4 = [NSURL URLWithString:self.searchResult.foto4];
}
if (![self.searchResult.foto5 isEqualToString:#""]) {
URL5 = [NSURL URLWithString:self.searchResult.foto5];
}
if (![self.searchResult.foto6 isEqualToString:#""]) {
URL6 = [NSURL URLWithString:self.searchResult.foto6];
}
if (URL1 !=NULL) {
[items addObject:URL1];
}
if (URL2 !=NULL) {
[items addObject:URL2];
}
if (URL3 !=NULL) {
[items addObject:URL3];
}
if (URL4 !=NULL) {
[items addObject:URL4];
}
if (URL5 !=NULL) {
[items addObject:URL5];
}
if (URL6 !=NULL) {
[items addObject:URL6];
}
Can this function be optimized ?
NSArray* photosToCheck = [NSArray arrayWithObjects:
self.searchResult.foto1, self.searchResult.foto2, self.searchResult.foto3, self.searchResult.foto4, self.searchResult.foto5, self.searchResult.foto6, nil];
for (NSString* photo in photosToCheck) {
if (photo.length > 0) {
NSURL* photoUrl = [NSURL URLWithString:photo];
[items addObject:photoUrl];
}
}
However, having properties named foto1, foto2, ... immediately tells us that an array should be used to hold data instead.
if you have exactly 6 fotos, leave it as it is.
Otherwise use an array of Urls, and loop through them.
Comparing against an empty string is equivalent to testing if the string has zero-length. It won't save much in terms of CPU time, but is at least easier to read. Also you can store the URL in the array when you set them, so there is no need to test them later:
if ([self.searchResult.foto1 length] > 0) {
URL1 = [NSURL URLWithString:self.searchResult.foto1];
[items addObject:URL1];
}
if ([self.searchResult.foto2 length] > 0) {
URL2 = [NSURL URLWithString:self.searchResult.foto2];
[items addObject:URL2];
}
// etc.
And if you don't actually use URL1 etc you can just put them straight into the array:
if ([self.searchResult.foto1 length] > 0) {
[items addObject:[NSURL URLWithString:self.searchResult.foto1]];
}
// etc.
Make self.searchResults a NSArray of Strings that you fill wherever you give values to the foto's
There are 2 ways to do for loops either
for(NSInteger x = 0;x<100;x++)
which will loop until the condition is false in this case x is greater than 99 or
for(NSObject *key in anArrayOfObjects)
which will loop through each object in the array
Null checking is always a good idea, the (NSString *) is typecasting the [NSNull null] to be a null NSString
url != (NSString *)[NSNull null]
You don't need the intermediate NSURL since you will already know if the foto value is empty or null so you can immediately put the object as a new NSURL into the array of items
[items addObject:[NSURL URLWithString:url]];
Final code
-(void)CheckUrls
{
self.items = [NSMutableArray array];
for(NSString *url in self.searchResult){
if( url != (NSString *)[NSNull null] && ![url isEqualToString:#""] ){
[items addObject:[NSURL URLWithString:url]];
}
}
}
With all the URL-handling objects lying around in the standard Cocoa libraries (NSURL, NSMutableURL, NSMutableURLRequest, etc), I know I must be overlooking an easy way to programmatically compose a GET request.
Currently I'm manually appending "?" followed by name value pairs joined by "&", but all of my name and value pairs need to be manually encoded so NSMutableURLRequest doesn't fail entirely when it tries to connect to the URL.
This feels like something I should be able to use a pre-baked API for.... is there anything out of the box to append an NSDictionary of query parameters to an NSURL? Is there another way I should approach this?
Introduced in iOS8 and OS X 10.10 is NSURLQueryItem, which can be used to build queries. From the docs on NSURLQueryItem:
An NSURLQueryItem object represents a single name/value pair for an item in the query portion of a URL. You use query items with the queryItems property of an NSURLComponents object.
To create one use the designated initializer queryItemWithName:value: and then add them to NSURLComponents to generate an NSURL. For example:
NSURLComponents *components = [NSURLComponents componentsWithString:#"http://stackoverflow.com"];
NSURLQueryItem *search = [NSURLQueryItem queryItemWithName:#"q" value:#"ios"];
NSURLQueryItem *count = [NSURLQueryItem queryItemWithName:#"count" value:#"10"];
components.queryItems = #[ search, count ];
NSURL *url = components.URL; // http://stackoverflow.com?q=ios&count=10
Notice that the question mark and ampersand are automatically handled. Creating an NSURL from a dictionary of parameters is as simple as:
NSDictionary *queryDictionary = #{ #"q": #"ios", #"count": #"10" };
NSMutableArray *queryItems = [NSMutableArray array];
for (NSString *key in queryDictionary) {
[queryItems addObject:[NSURLQueryItem queryItemWithName:key value:queryDictionary[key]]];
}
components.queryItems = queryItems;
I've also written a blog post on how to build URLs with NSURLComponents and NSURLQueryItems.
You can create a category for NSDictionary to do this -- there isn't a standard way in the Cocoa library that I could find either. The code that I use looks like this:
// file "NSDictionary+UrlEncoding.h"
#import <cocoa/cocoa.h>
#interface NSDictionary (UrlEncoding)
-(NSString*) urlEncodedString;
#end
with this implementation:
// file "NSDictionary+UrlEncoding.m"
#import "NSDictionary+UrlEncoding.h"
// helper function: get the string form of any object
static NSString *toString(id object) {
return [NSString stringWithFormat: #"%#", object];
}
// helper function: get the url encoded string form of any object
static NSString *urlEncode(id object) {
NSString *string = toString(object);
return [string stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
}
#implementation NSDictionary (UrlEncoding)
-(NSString*) urlEncodedString {
NSMutableArray *parts = [NSMutableArray array];
for (id key in self) {
id value = [self objectForKey: key];
NSString *part = [NSString stringWithFormat: #"%#=%#", urlEncode(key), urlEncode(value)];
[parts addObject: part];
}
return [parts componentsJoinedByString: #"&"];
}
#end
I think the code's pretty straightforward, but I discuss it in some more detail at http://blog.ablepear.com/2008/12/urlencoding-category-for-nsdictionary.html.
I wanted to use Chris's answer, but it wasn't written for Automatic Reference Counting (ARC) so I updated it. I thought I'd paste my solution in case anyone else has this same issue. Note: replace self with the instance or class name where appropriate.
+(NSString*)urlEscapeString:(NSString *)unencodedString
{
CFStringRef originalStringRef = (__bridge_retained CFStringRef)unencodedString;
NSString *s = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,originalStringRef, NULL, (CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ", kCFStringEncodingUTF8);
CFRelease(originalStringRef);
return s;
}
+(NSString*)addQueryStringToUrlString:(NSString *)urlString withDictionary:(NSDictionary *)dictionary
{
NSMutableString *urlWithQuerystring = [[NSMutableString alloc] initWithString:urlString];
for (id key in dictionary) {
NSString *keyString = [key description];
NSString *valueString = [[dictionary objectForKey:key] description];
if ([urlWithQuerystring rangeOfString:#"?"].location == NSNotFound) {
[urlWithQuerystring appendFormat:#"?%#=%#", [self urlEscapeString:keyString], [self urlEscapeString:valueString]];
} else {
[urlWithQuerystring appendFormat:#"&%#=%#", [self urlEscapeString:keyString], [self urlEscapeString:valueString]];
}
}
return urlWithQuerystring;
}
The other answers work great if the values are strings, however if the values are dictionaries or arrays then this code will handle that.
Its important to note that there is no standard way of passing an array/dictionary via the query string but PHP handles this output just fine
-(NSString *)serializeParams:(NSDictionary *)params {
/*
Convert an NSDictionary to a query string
*/
NSMutableArray* pairs = [NSMutableArray array];
for (NSString* key in [params keyEnumerator]) {
id value = [params objectForKey:key];
if ([value isKindOfClass:[NSDictionary class]]) {
for (NSString *subKey in value) {
NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)[value objectForKey:subKey],
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
[pairs addObject:[NSString stringWithFormat:#"%#[%#]=%#", key, subKey, escaped_value]];
}
} else if ([value isKindOfClass:[NSArray class]]) {
for (NSString *subValue in value) {
NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)subValue,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
[pairs addObject:[NSString stringWithFormat:#"%#[]=%#", key, escaped_value]];
}
} else {
NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)[params objectForKey:key],
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
[pairs addObject:[NSString stringWithFormat:#"%#=%#", key, escaped_value]];
[escaped_value release];
}
}
return [pairs componentsJoinedByString:#"&"];
}
Examples
[foo] => bar
[translations] =>
{
[one] => uno
[two] => dos
[three] => tres
}
foo=bar&translations[one]=uno&translations[two]=dos&translations[three]=tres
[foo] => bar
[translations] =>
{
uno
dos
tres
}
foo=bar&translations[]=uno&translations[]=dos&translations[]=tres
I refactored and converted to ARC answer by AlBeebe
- (NSString *)serializeParams:(NSDictionary *)params {
NSMutableArray *pairs = NSMutableArray.array;
for (NSString *key in params.keyEnumerator) {
id value = params[key];
if ([value isKindOfClass:[NSDictionary class]])
for (NSString *subKey in value)
[pairs addObject:[NSString stringWithFormat:#"%#[%#]=%#", key, subKey, [self escapeValueForURLParameter:[value objectForKey:subKey]]]];
else if ([value isKindOfClass:[NSArray class]])
for (NSString *subValue in value)
[pairs addObject:[NSString stringWithFormat:#"%#[]=%#", key, [self escapeValueForURLParameter:subValue]]];
else
[pairs addObject:[NSString stringWithFormat:#"%#=%#", key, [self escapeValueForURLParameter:value]]];
}
return [pairs componentsJoinedByString:#"&"];
}
- (NSString *)escapeValueForURLParameter:(NSString *)valueToEscape {
return (__bridge_transfer NSString *) CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef) valueToEscape,
NULL, (CFStringRef) #"!*'();:#&=+$,/?%#[]", kCFStringEncodingUTF8);
}
If you are already using AFNetworking (as was the case with me), you can use it's class AFHTTPRequestSerializer to create the required NSURLRequest.
[[AFHTTPRequestSerializer serializer] requestWithMethod:#"GET" URLString:#"YOUR_URL" parameters:#{PARAMS} error:nil];
In case you only require the URL for your work, use NSURLRequest.URL.
Here is a simple example in Swift (iOS8+):
private let kSNStockInfoFetchRequestPath: String = "http://dev.markitondemand.com/Api/v2/Quote/json"
private func SNStockInfoFetchRequestURL(symbol:String) -> NSURL? {
if let components = NSURLComponents(string:kSNStockInfoFetchRequestPath) {
components.queryItems = [NSURLQueryItem(name:"symbol", value:symbol)]
return components.URL
}
return nil
}
I took Joel's recommendation of using URLQueryItems and turned into a Swift Extension (Swift 3)
extension URL
{
/// Creates an NSURL with url-encoded parameters.
init?(string : String, parameters : [String : String])
{
guard var components = URLComponents(string: string) else { return nil }
components.queryItems = parameters.map { return URLQueryItem(name: $0, value: $1) }
guard let url = components.url else { return nil }
// Kinda redundant, but we need to call init.
self.init(string: url.absoluteString)
}
}
(The self.init method is kinda cheesy, but there was no NSURL init with components)
Can be used as
URL(string: "http://www.google.com/", parameters: ["q" : "search me"])
I've got another solution:
http://splinter.com.au/build-a-url-query-string-in-obj-c-from-a-dict
+(NSString*)urlEscape:(NSString *)unencodedString {
NSString *s = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ",
kCFStringEncodingUTF8);
return [s autorelease]; // Due to the 'create rule' we own the above and must autorelease it
}
// Put a query string onto the end of a url
+(NSString*)addQueryStringToUrl:(NSString *)url params:(NSDictionary *)params {
NSMutableString *urlWithQuerystring = [[[NSMutableString alloc] initWithString:url] autorelease];
// Convert the params into a query string
if (params) {
for(id key in params) {
NSString *sKey = [key description];
NSString *sVal = [[params objectForKey:key] description];
// Do we need to add ?k=v or &k=v ?
if ([urlWithQuerystring rangeOfString:#"?"].location==NSNotFound) {
[urlWithQuerystring appendFormat:#"?%#=%#", [Http urlEscape:sKey], [Http urlEscape:sVal]];
} else {
[urlWithQuerystring appendFormat:#"&%#=%#", [Http urlEscape:sKey], [Http urlEscape:sVal]];
}
}
}
return urlWithQuerystring;
}
You can then use it like so:
NSDictionary *params = #{#"username":#"jim", #"password":#"abc123"};
NSString *urlWithQuerystring = [self addQueryStringToUrl:#"https://myapp.com/login" params:params];
-(NSString*)encodeDictionary:(NSDictionary*)dictionary{
NSMutableString *bodyData = [[NSMutableString alloc]init];
int i = 0;
for (NSString *key in dictionary.allKeys) {
i++;
[bodyData appendFormat:#"%#=",key];
NSString *value = [dictionary valueForKey:key];
NSString *newString = [value stringByReplacingOccurrencesOfString:#" " withString:#"+"];
[bodyData appendString:newString];
if (i < dictionary.allKeys.count) {
[bodyData appendString:#"&"];
}
}
return bodyData;
}
Yet another solution, if you use RestKit there's a function in RKURLEncodedSerialization called RKURLEncodedStringFromDictionaryWithEncoding that does exactly what you want.
Simple way of converting NSDictionary to url query string in Objective-c
Ex: first_name=Steve&middle_name=Gates&last_name=Jobs&address=Palo Alto, California
NSDictionary *sampleDictionary = #{#"first_name" : #"Steve",
#"middle_name" : #"Gates",
#"last_name" : #"Jobs",
#"address" : #"Palo Alto, California"};
NSMutableString *resultString = [NSMutableString string];
for (NSString* key in [sampleDictionary allKeys]){
if ([resultString length]>0)
[resultString appendString:#"&"];
[resultString appendFormat:#"%#=%#", key, [sampleDictionary objectForKey:key]];
}
NSLog(#"QueryString: %#", resultString);
Hope will help :)
If you are already using AFNetwork, you can use their built in serializer to to produce an encoded URL;
NSString *baseURL = #"https://api.app.com/parse";
NSDictionary *mutableParameters = [[NSMutableDictionary alloc] initWithObjectsAndKeys:#"true",#"option1", data, #"option2", token, #"token", #"3.0", #"app", nil];
NSURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:#"GET" URLString:baseURL parameters:mutableParameters error:nil];
NSString *urlPath = request.URL.absoluteString;
NSLog(#"%#", urlPath); // https://api.app.com/parse?option1=true&option2=datavalue&token=200%3ATEST%3AENCODE ....
Note; this is an extension to an above answer. The edit queue is full so cannot be added to the existing answer.