Objective-C - Checking if URL exists - iphone

I have a for-loop that currently loops 4 times.
//Add all the URLs from the server to the array
for (int i = 1; i <= 5; i++){
NSString *tempString = [[NSString alloc] initWithFormat : #"http://photostiubhart.comoj.com/GalleryImages/%dstiubhart1.jpg", i];
[myURLS addObject: [NSURL URLWithString:tempString]];
[tempString release];
}
As you can see the URL has a digit in it that get incremented by 1 each loop to create a new URL where the next image will be. However, the amount of images on the server won't necessarily be 4, it could be a lot more or even less. My problem is this, is there a way I can check if there is an image stored at the URL? And if there is not, break the loop and continue program execution?
Thanks,
Jack

Here is idea to check with HTTP response
NSURLRequest *request;
NSURLResponse *response = nil;
NSError **error=nil;
NSData *data=[[NSData alloc] initWithData:[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:error]];
NSString* retVal = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// you can use retVal , ignore if you don't need.
NSInteger httpStatus = [((NSHTTPURLResponse *)response) statusCode];
NSLog(#"responsecode:%d", httpStatus);
// there will be various HTTP response code (status)
// you might concern with 404
if(httpStatus == 404)
{
// do your job
}
or
while(httpStatus == 200){
static int increment = 0;
increment++;
// check other URL yoururl/somthing/increment++
}
but it will be slow. what my suggestion is, if you are using your own webserver, then, you can send all the image information initially. I'm sure you are doing this job on annonymous or other website :)
Let me know if it helps you or not

Here is simplest way to check if URL is valid:
NSURL *URL = [NSURL URLWithString:#"www.your.unvalidated.yet/url"];
if ( [[UIApplication sharedApplication] canOpenURL:[URL absoluteURL]] )
{
//your link is ok
}

Related

Send NSURLConnection request multiple times with different url's in a for loop

I have an array of addresses that I need to convert to Lat/Long using Google's Geocode api. I am feeding an address and the city into the Google Geocode URL, which forms a correct connection url.
Basically I want to be able to use a for loop to create multiple NSURLConnection requests, returning multiple responses.
-(void)setString{
for (int i = 0; i < [businessArray count]; i ++)
{
NSString *address = [addressArray objectAtIndex:0];
NSString *city = [locationDict valueForKey:#"city"];
NSString *geocodeURL = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#,+%#,&sensor=true", address, city];
geocodeURL = [geocodeURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:geocodeURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10];
NSLog(#"%#", request);
geoCodeConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
if (geoCodeConnection)
{
responseData = [NSMutableData data];
connectionIsActive = YES;
NSLog(#"connection active");
} else {
NSLog(#"connection failed");
connectionIsActive = NO;
}
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSError *jsonError = nil;
SBJsonParser *json = [[SBJsonParser alloc] init];
NSDictionary *parsedJSON = [json objectWithString:responseString error:&jsonError];
NSString *lat= [[[[parsedJSON valueForKey:#"results"] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lat"];
NSString *lng= [[[[parsedJSON valueForKey:#"results"] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lng"];
NSLog(#"lat = %# long= %#", lat, lng);
connectionIsActive = NO;
[geoCodeLatArray addObject:lat];
[geoCodeLngArray addObject:lng];
NSLog(#"geoCodeArrayLat: %#", geoCodeLatArray);
}
Right now the code returns only the last address' lat and long. How can I send multiply requests and return multiply responses with JSON?
Try this I am using this,
for(int i=0;i< businessArray.count;i++)
{
NSString *address = [addressArray objectAtIndex:i];
NSString *city = [locationDict valueForKey:#"city"];
NSString *address = [NSString stringWithFormat:#"%#,%#", address, city];
CLLocationCoordinate2D location = [self geoCodeUsingAddress:address];
// then here store the location.latitude in lat array and location.longitude in long array.
}
- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)address
{
NSString *esc_addr = [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", esc_addr];
NSDictionary *googleResponse = [[NSString stringWithContentsOfURL: [NSURL URLWithString: req] encoding: NSUTF8StringEncoding error: NULL] JSONValue];
NSDictionary *resultsDict = [googleResponse valueForKey: #"results"];
NSDictionary *geometryDict = [resultsDict valueForKey: #"geometry"];
NSDictionary *locationDict = [geometryDict valueForKey: #"location"];
NSArray *latArray = [locationDict valueForKey: #"lat"];
NSString *latString = [latArray lastObject];
NSArray *lngArray = [locationDict valueForKey: #"lng"];
NSString *lngString = [lngArray lastObject];
CLLocationCoordinate2D location;
location.latitude = [latString doubleValue];
location.longitude = [lngString doubleValue];
return location;
}
Update to the above function:
- (CLLocationCoordinate2D) geoCodeUsingAddress:(NSString *)address
{
double latitude = 0, longitude = 0;
NSString *esc_addr = [address stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *req = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?sensor=false&address=%#", esc_addr];
NSString *result = [NSString stringWithContentsOfURL:[NSURL URLWithString:req] encoding:NSUTF8StringEncoding error:NULL];
if (result) {
NSScanner *scanner = [NSScanner scannerWithString:result];
if ([scanner scanUpToString:#"\"lat\" :" intoString:nil] && [scanner scanString:#"\"lat\" :" intoString:nil]) {
[scanner scanDouble:&latitude];
if ([scanner scanUpToString:#"\"lng\" :" intoString:nil] && [scanner scanString:#"\"lng\" :" intoString:nil]) {
[scanner scanDouble:&longitude];
}
}
}
CLLocationCoordinate2D location;
location.latitude = latitude;
location.longitude = longitude;
return location;
}
This worked for me.
You might approach the problem using an asynchronous method that performs the request and has a completion block which will be called when the result is available. This completion block provides a parameter result which is the result of the connection request.
This method may be declared as follows:
typedef void (^completion_block_t) (id result);
- (void) fetchGeoCoordinateForAddress:(NSString*)address
completionHandler:(completion_block_t)completionHandler;
Say, if the request succeeds the parameter result in the block is a JSON representation of the response data. Otherwise, result is an NSError object indicating the error. But the exact details depend on how you implement the method fetchGeoCoordinateForAddress:completionHandler:.
Now you can setup the loop as follows:
for (NSString* address in addresses)
{
[self fetchGeoCoordinateForAddress:address completionHandler:^(id result) {
if (![result isKindOfError:[NSError class]]) // check if result is an error
{
// Note: result is not nil and is a NSDictionary representation of JSON.
// Retrieve the "location" from the response:
NSDictionary* location = result[#"results"][#"geometry"][#"location"];
// Multiple request can occur at the same time! Thus, we need to
// synchronize access to the result array "myLocations" through
// accessing it *exclusively and everywhere* on the main thread:
dispatch_async(dispatch_get_main_queue(), ^{
[self.myLocations addObject:location];
});
}
else {
// got error
DebugLog(#"ERROR: %#", result);
}
}
}
Note: your actual code may differ slightly depending on the actual JSON and other details.
Regarding the implementation of method fetchGeoCoordinateForAddress:completionHandler: you have a few options:
Use a third party library and implement a simple convenience wrapper fetchGeoCoordinateForAddress:completionHandler:.
Create your own "MyHTTPConnectionOperation" class that encapsulates a NSURLConnection and the response data and couple of other useful state info in a dedicated class. This class executes the request asynchronously via start method and has a completion handler. Basically, all third party network libraries will use this approach. Then implement the wrapper.
Use NSURLConnection's asynchronous convenient method if it is sufficient and works in your context. This is the fastest to implement, but least flexible approach and may not work in all cases and may also work only suboptimal.
Edit:
A couple of hints:
If possible, use NSJSONSerialization for parsing JSON and creating a Foundation representation. Other third party libraries only offer a slight advantage if you have special requirements, e.g. you need "chunked parsing with NSData objects" - which is useful when you want to download and parse simultaneously. Or you need to create other representations than Foundation - say a C++ container or you want directly create a Model with SAX style parsing. Or, you need better performance and lower memory food print since you are receiving ultra large strings which you want to save to disk. NSJSONSerialization became quite fast recently, so "performance" alone shouldn't be an argument today.
The timeout for the request shall be not that low as 10 seconds. In a cellular connection, this is too less. Leave it at the default.
If you plan to implement your own "HTTPConnectionOperation" class, I've put a very limited sample on gist here which can give you a jump start.
I think you have to start with AFNetworking
AFNetworking1
AFNetworking2
because AFNetworking gives a lot of power and flexibility in terms of scheduling and queueing requests as well as pausing and cancelling requests.

How to get find and get URL in a NSString in iPhone?

I have a text with http:// in NSString. I want to get that http link from the NSString. How can i get the link/url from the string? Eg: 'Stack over flow is very useful link for the beginners https://stackoverflow.com/'. I want to get the 'https://stackoverflow.com/' from the text. How can i do this? Thanks in advance.
I am not sure what you exactly mean by link but if you want to convert your NSString to NSURL than you can do the following:
NSString *urlString = #"http://somepage.com";
NSURL *url = [NSURL URLWithString:urlString];
EDIT
This is how to get all URLs in a given NSString:
NSString *str = #"This is a grate website http://xxx.xxx/xxx you must check it out";
NSArray *arrString = [str componentsSeparatedByString:#" "];
for(int i=0; i<arrString.count;i++){
if([[arrString objectAtIndex:i] rangeOfString:#"http://"].location != NSNotFound)
NSLog(#"%#", [arrString objectAtIndex:i]);
}
Rather than splitting the string into an array and messing about that way, you can just search for the substring beginning with #"http://":
NSString *str = #"Stack over flow is very useful link for the beginners http://stackoverflow.com/";
// get the range of the substring starting with #"http://"
NSRange rng = [str rangeOfString:#"http://" options:NSCaseInsensitiveSearch];
// Set up the NSURL variable to hold the created URL
NSURL *newURL = nil;
// Make sure that we actually have found the substring
if (rng.location == NSNotFound) {
NSLog(#"URL not found");
// newURL is initialised to nil already so nothing more to do.
} else {
// Get the substring from the start of the found substring to the end.
NSString *urlString = [str substringFromIndex:rng.location];
// Turn the string into an URL and put it into the declared variable
newURL = [NSURL URLWithString:urlString];
}
try this :
nsstring *str = #"Stack over flow is very useful link for the beginners http://stackoverflow.com/";
nsstring *http = #"http";
nsarray *arrURL = [str componentsSeparatedByString:#"http"];
this will give two objects in the nsarray. 1st object will be having:Stack over flow is very useful link for the beginners and 2nd will be : ://stackoverflow.com/ (i guess)
then you can do like:
NSString *u = [arrURL lastObject];
then do like:
nsstring *http = [http stringByAppendingFormat:#"%#",u];
Quite a lengthy,but i think that would work for you. Hope that helps you.

How do I download a file from S3 to an iPhone application?

I am new to iPhone development. I am developing an iPhone application which needs to open files stored on Amazon's S3 service.
How do I download a file from S3 to my iPhone application? I have tried Amazon's SDK, but they don't seem to provide a means of downloading and saving a file. How do I go about obtaining a file's URL from S3 and saving it in my application?
I always use the ASIHttpRequest library to do this and it's quite simple, here's a sample code from their website:
NSString *secretAccessKey = #"my-secret-access-key";
NSString *accessKey = #"my-access-key";
NSString *bucket = #"my-bucket";
NSString *path = #"path/to/the/object";
ASIS3ObjectRequest *request = [ASIS3ObjectRequest requestWithBucket:bucket key:path];
[request setSecretAccessKey:secretAccessKey];
[request setAccessKey:accessKey];
[request startSynchronous];
if (![request error]) {
NSData *data = [request responseData];
} else {
NSLog(#"%#",[[request error] localizedDescription]);
}
You can't get easier than this :)
If you don't have the luxury of simplicity using ASI, and/or are stuck with AWSiOS SDK, it's not a lot different:
/* borrowed from Maurício Linhares's answer */
NSString *secretAccessKey = #"my-secret-access-key";
NSString *accessKey = #"my-access-key";
NSString *bucket = #"my-bucket";
NSString *path = #"path/to/the/object";
/********************************************/
AmazonCredentials *credentials = [[AmazonCredentials alloc] initWithAccessKey: accessKey withSecretKey: secretAccessKey];
AmazonS3Client *connection = [[AmazonS3Client alloc] initWithCredentials: credentials];
S3GetObjectRequest *downloadRequest = [[[S3GetObjectRequest alloc] initWithKey:path withBucket: bucket] autorelease];
[downloadRequest setDelegate: self]; /* only needed for delegate (see below) */
S3GetObjectResponse *downloadResponse = [self.awsConnection getObject: downloadRequest];
Then you can look at downloadResponse.body and downloadResponse.httpStatusCode, preferable in a delegate:
-(void)request: (S3Request *)request didCompleteWithResponse: (S3Response *) response {
NSLog(#"Download finished (%d)",response.httpStatusCode);
/* do something with response.body and response.httpStatusCode */
/* if you have multiple requests, you can check request arg */
}

iphone: NSMutableURLRequest returns strange characters for MS Word style apostrophe

We are pulling content off our website using XML/NSMutableURLRequest and sometimes it pulls through the "curly" style apostrophe and quotes, ’ rather than '. NSMutableURLRequest seems to hate these and turns them into the strange \U00e2\U0080\U0099 string.
Is there something that I can to do prevent this? I am using the GET method, so should I be somehow telling it to use UTF-8? Or, am I missing something?
UIApplication* app = [UIApplication sharedApplication];
app.networkActivityIndicatorVisible = YES;
NSString *urlStr = [NSString stringWithFormat:#"%#",url];
NSURL *serviceUrl = [NSURL URLWithString:urlStr];
NSMutableURLRequest *serviceRequest = [NSMutableURLRequest requestWithURL:serviceUrl];
[serviceRequest setHTTPMethod:#"GET"];
NSURLResponse *serviceResponse;
NSError *serviceError;
app.networkActivityIndicatorVisible = NO;
return [NSURLConnection sendSynchronousRequest:serviceRequest returningResponse:&serviceResponse error:&serviceError];
NSURLConnection returns an NSData response. You can take that NSData response and turn it into a string. Then take this string, turn it back into a NSData object, properly UTF-8 encoding it along the way, and feed it to NSXMLParser.
Example: (Assuming response is the NSData response from your request)
// long variable names for descriptive purposes
NSString* xmlDataAsAString = [[[NSString alloc] initWithData:response] autorelease];
NSData* toFeedToXMLParser = [xmDataAsAString dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser* parser = [[[NSXMLParser alloc] initWithData:toFeedToXMLParser] autorelease];
// now utilize parser...
I would suggest replacing those characters using stringByReplacingCharactersInRange:withString: to replace the unwanted strings.
NSString *currentTitle = #"Some string with a bunch of stuff in it.";
//Create a new range for each character.
NSRange rangeOfDash = [currentTitle rangeOfString:#"character to replace"];
NSString *location = (rangeOfDash.location != NSNotFound) ? [currentTitle substringToIndex:rangeOfDash.location] : nil;
if(location){
currentTitle = [[currentTitle stringByReplacingOccurrencesOfString:location withString:#""] mutableCopy];
}
I've done this in the past to handle the same problem you describe.
Try using the stringByReplacingPercentEscapesUsingEncoding:

function to get the file name of an URL

I have some source code to get the file name of an url
for example:
http://www.google.com/a.pdf
I hope to get a.pdf
because the way to join 2 NSStrings I can get is 'appendString' which only for adding a string at right side, so I planned to check each char one by one from the right side of string 'http://www.google.com/a.pdf', when it reach at the char '/', stop the checking, return string fdp.a , after that I change fdp.a to a.pdf
source codes are below
-(NSMutableString *) getSubStringAfterH : originalString:(NSString *)s0
{
NSInteger i,l;
l=[s0 length];
NSMutableString *h=[[NSMutableString alloc] init];
NSMutableString *ttt=[[NSMutableString alloc] init ];
for(i=l-1;i>=0;i--) //check each char one by one from the right side of string 'http://www.google.com/a.pdf', when it reach at the char '/', stop
{
ttt=[s0 substringWithRange:NSMakeRange(i, 1)];
if([ttt isEqualToString:#"/"])
{
break;
}
else
{
[h appendString:ttt];
}
}
[ttt release];
NSMutableString *h1=[[[NSMutableString alloc] initWithFormat:#""] autorelease];
for (i=[h length]-1;i>=0;i--)
{
NSMutableString *t1=[[NSMutableString alloc] init ];
t1=[h substringWithRange:NSMakeRange(i, 1)];
[h1 appendString:t1];
[t1 release];
}
[h release];
return h1;
}
h1 can reuturn the coorect string a.pdf, but if it returns to the codes where it was called, after a while system reports
'double free
*** set a breakpoint in malloc_error_break to debug'
I checked a long time and foudn that if I removed the code
ttt=[s0 substringWithRange:NSMakeRange(i, 1)];
everything will be Ok (of course getSubStringAfterH can not returns the corrent result I expected.), no error reported.
I try to fix the bug a few hours, but still no clue.
Welcome any comment
Thanks
interdev
The following line does the job if url is a NSString:
NSString *filename = [url lastPathComponent];
If url is a NSURL, then the following does the job:
NSString *filename = [[url path] lastPathComponent];
Try this:
Edit: from blow comment
NSString *url = #"http://www.google.com/a.pdf";
NSArray *parts = [url componentsSeparatedByString:#"/"];
NSString *filename = [parts lastObject];
I think if you have already had the NSURL object, there is lastPathComponent method available from the iOS 4 onwards.
NSURL *url = [NSURL URLWithString:#"http://www.google.com/a.pdf"];
NSString *filename = [url lastPathComponent];
Swift 3
Let's say that your url is http://www.google.com/a.pdf
let filename = url.lastPathComponent
\\filename = "a.pdf"
This is more error free and meant for getting the localized name in the URL.
NSString *localizedName = nil;
[url getResourceValue:&localizedName forKey:NSURLLocalizedNameKey error:NULL];
I haven't tried this yet, but it seems like you might be trying to do this the hard way. The iPhone libraries have the NSURL class, and I imagine that you could simply do:
NSString *url = [NSURL URLWithString:#"http://www.google.com/a.pdf"];
NSString *path = [url path];
Definitely look for a built in function. The libraries have far more testing and will handle the edge cases better than anything you or I will write in an hour or two (generally speaking).