UIWebView How to get correct URL? - ios

I am making a simple web browser by using UIWebView. User enters an address on the address bar -> check it.
1.If the text is url -> load the request
2.If the text is string -> perform a google search
In the first case, if string has the format: abc.xyz, how to add a scheme and host to it?
Example: user enters google.com -> correct to https://google.com
engadget.com -> https://www.engadget.com.
My problem is how to know which part had to add to url(http, https, with or without www).
Update:
use NSURLSeassion to test connect
- (void)checkRequest:(NSString*)urlRequest
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlRequest]];
[request setHTTPMethod:#"HEAD"];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode == 200)
NSLog(#"Correct url");
// check status code here
}
if (error) {
// handle other errors here
}
// handle data here
}];
[task resume];
}
Update 2
Don't need to check url, add http:// scheme and website will automatically redirect to the correct destination.

in your case i think you need to perform a HEAD request and check the result.
For example, with your sample url http://engadget.com. if it response not exists, add www to this url and try again.
NSMutableURLRequest request = [NSMutableURLRequest requestWithURL:inURL];
[request setHTTPMethod:#"HEAD"];
NSURLConnection connection = [NSURLConnection connectionWithRequest:request delegate:self];
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if ([(NSHTTPURLResponse *)response statusCode] == 200) {
// url exists
}
}

Related

NSURLConnection send request after finish all process

I have a nested loop of sending the request.
-(void) download
{
for(NSString *id in array)
{
//init with request and start the connection
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy: NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request deletegate:self];
[conn start];
}
}
-(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data
{
//enter here secondly
}
-(void) connectionDidFinishLoading:(NSURLConnection *) connection
{
//enter here last, after finish the for loop
//my intention is use the downloaded data to do something before sending a new request.
}
The problem is that I want to enter "-(void) connectionDidFinishLoading:(NSURLConnection *) connection" first before send the request again in the for loop.
But currently it will finish the for loop and sent all the request before enter to "-(void) connectionDidFinishLoading:(NSURLConnection *) connection".
You Should Try This NSURLConnection is deprecated in iOS9
for (NSString *URL in URLArray) {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// check error and/or handle response here
}];
[task resume];
}
and use dispatch_group_t group = dispatch_group_create();
add line to for loop dispatch_group_enter(group); will call
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// Request Finish
});
for your goal
In your case you need to try block function because as per your requirement you want response of the first connection for another request.
for(NSString* url in array)
{
// Generate a NSURLRequest object from the address of the API.
NSURL *url = [NSURL URLWithString:urlLink];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Send the request asynchronous request using block!
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"Error in updateInfoFromServer: %# %#", error, [error localizedDescription]);
} else if (!response) {
NSLog(#"Could not reach server!");
} else if (!data) {
NSLog(#"Server did not return any data!");
} else {
[self doStuffWithData:data];
}
}];
}
URL loading is not a synchronous operation (or at least should never be done synchronously), because it can take up to 90 seconds just for a DNS lookup failure, and almost infinitely long if the server keeps dribbling out data. If you block the main thread for even a fraction of that amount of time, iOS will kill your app.
Instead of scheduling the requests in a loop and waiting for them to finish, you need to schedule the first request (and only the first request). Then, in your connectionDidFinishLoading: method (and maybe your connection:DidFailWithError: method), schedule the next request.
With that said, unless you still need to support iOS 6/10.8 and earlier, you should probably be using NSURLSession. (The same general advice applies; the delegate method names are changed to protect the guilty.)

IOS: Check existence of remote file

Is there any resource efficient way (something that does not tie up the main thread) in IOS to check the existence of a remote file?
I have user images stored on a server. While there is a consistent url scheme, some images are .jpg, others are .gif, etc. so to get the correct image name, I need to check does user/file.gif exist, user/file.jpg exist etc. in order to download the file to the IOS app.
I found this code in another answer in IOS
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"HEAD"];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
But I am not sure how to use it. Ideally, I would like to get a boolean yes or no as to whether the .gif file exists, the .jpg file exists etc for the users profile pic so I can fill in the correct name to download the user pic.
The alternative would be to write a service on the back end to return the file but wondering if it can all be done in IOS.
Thanks for any suggestions.
**Use this function below to check whether file exists at specified url**
+(void)checkWhetherFileExistsIn:(NSURL *)fileUrl Completion:(void (^)(BOOL success, NSString *fileSize ))completion
{
//MAKING A HEAD REQUEST
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileUrl];
request.HTTPMethod = #"HEAD";
request.timeoutInterval = 3;
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
if (connectionError == nil) {
if ((long)[httpResponse statusCode] == 200)
{
//FILE EXISTS
NSDictionary *dic = httpResponse.allHeaderFields;
NSLog(#"Response 1 %#",[dic valueForKey:#"Content-Length"]);
completion(TRUE,[dic valueForKey:#"Content-Length"]);
}
else
{
//FILE DOESNT EXIST
NSLog(#"Response 2");
completion(FALSE,#"");
}
}
else
{
NSLog(#"Response 3");
completion(FALSE,#"");
}
}];
}

How to send an asynchronous post request in iOS

I need some help with a LoginViewController.
Basically I have a small app, and I need to post some data to the app and Im new to POST and JSON. If I can get some help and understanding that would be highly appreciated. Below are some requirements im working with. My .m file is labled as LoginViewController. This is what I have so far
-(void)setRequest {
#pragma mark NSURLConnection Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
_responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable you declared
[_responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
// Check the error var
}
-(void)PostRequest{
// Create the request.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://dev.apppartner.com/AppPartnerProgrammerTest/scripts/login.php"]];
// Specify that it will be a POST request
request.HTTPMethod = #"POST";
// This is how we set header fields
[request setValue:#"application/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
// Convert your data and set your request's HTTPBody property
NSString *stringData = #"some data";
NSData *requestBodyData = [stringData dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = requestBodyData;
// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
}
I dont know if I'm even setting this up right. I saw many hTTP posts and what not, but im still confused on how I write this syntax and do I need to add anything additional.
I need to:
Send an asynchronous POST request to "some url"
The POST request must contain the parameters 'username' and 'password'
Will receive a JSON response back with a 'code' and a 'message'
Display the parsed code and message in a UIAlert along with how long the api call took in miliseconds
The only valid login is username: Super password: qwerty
When a login is successful, tapping 'OK' on the UIAlert should bring us back to the MainMenuViewController
I'm assuming the methods inside methods are a typo.
Unless you have a particular reason to implement all those delegate methods, you're probably better off using either
NSURLSessionDataTask *task =
[[NSURLSession sharedSession] dataTaskWithRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
// Code to run when the response completes...
}];
[task resume];
or the equivalent using NSURLConnection's sendAsynchronousRequest:queue:completionHandler: method if you still need to support iOS 6 and earlier and/or OS X v10.8 and earlier.
But the big thing you're missing is the encoding of the request body. To do that, you'll probably want to use URL encoding and specify the appropriate MIME type for that as shown here:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/URLLoadingSystem/WorkingwithURLEncoding/WorkingwithURLEncoding.html
Basically, you construct a string by string concatenation in the form "user=ENCODEDUSERNAME&pass=ENCODEDPASSWORD" where the two encoded values are constructed like this:
NSString *encodedString = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(__bridge NSString *)originalString,
NULL,
CFSTR(":/?#[]#!$&'()*+,;="),
kCFStringEncodingUTF8);
Do not be tempted to use stringByAddingPercentEscapesUsingEncoding: and friends. They will do the wrong thing if your strings contain certain reserved URL characters.
I would suggest that you try working with AFNetworking Library.
You can find the code here.
And a very good tutorial here.
You can do like that for this.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request addValue:#"YourUsername" forHTTPHeaderField:#"Username"];
[request addValue:#"YourPassword" forHTTPHeaderField:#"Password"];
[NSURLConnection
sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// TODO: Handle/Manage your response ,Data & errors
}];
-(IBAction)registerclick:(id)sender
{
if (_password.text==_repassword.text)
{
[_errorlbl setHidden:YES];
NSString *requstUrl=[NSString stringWithFormat:#"http://irtech.com/fresery/index.php?route=api/fresery/registerCustomer"];
NSString *postString=[NSString stringWithFormat:#"name=asd&email=sooraj&phonenumber=8111&password=soorajsnr&type=1&facebookid=&image_path="];
// _name.text,_email.text,_mobile.text,_password.text
NSData *returnData=[[NSData alloc]init];
NSMutableURLRequest *request=[[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:requstUrl]];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"%lu", (unsigned long)[postString length]] forHTTPHeaderField:#"Content-length"];
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
resp=[NSJSONSerialization JSONObjectWithData:returnData options:NSJSONReadingMutableContainers error:nil];
c=[[resp valueForKey:#"status" ]objectAtIndex:0];
b=[[resp valueForKey:#"message"]objectAtIndex:0];

NSTimer? - Check Connection iOS

I am using the following method to check if my app has a connection. It's simple and works great for my needs.
+ (void)checkInternet:(connection)block
{
NSURL *url = [NSURL URLWithString:#"http://www.google.com/"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = #"HEAD";
request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
request.timeoutInterval = 10.0;
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
block([(NSHTTPURLResponse *)response statusCode] == 200);
}];
}
However, what I'd like to do is if the status doesn't return 200, I'd like to check again, at least a couple of times. What's the best way to do this with 1 second intervals?
Below is how I'm calling the above method.
[self checkInternet:^(BOOL internet)
{
if (internet)
{
// "Internet" aka Google
}
else
{
// No "Internet" aka no Google
}
}];
I use Reachability for detecting general network connection issues (See end of answer). I use the following method for executing retries.
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
You could adapt your system something like the following to have a new class method which has an optional number of retries.
NB. Not tested the following. It is just to give you the general idea.
// Variable to track number of retries left. If you had a shared instance
// a property would be easier.
static NSUInteger maxConnectionTries = 0;
// New method which lets you pass a retry count.
+ (void)checkInternet:(connection)block withMaxTries:(NSUInteger)maxTries
{
maxConnectionTries=maxTries;
[self checkInternet:block];
}
// Your original code extended to retry by calling itself when code 200
// is seen on a delay of 1s. Defaults to old code when retry limit exceeded
// or non 200 code received.
+ (void)checkInternet:(connection)block
{
NSURL *url = [NSURL URLWithString:#"http://www.google.com/"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = #"HEAD";
request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
request.timeoutInterval = 10.0;
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
if ([(NSHTTPURLResponse *)response statusCode] != 200 &&
maxConnectionRetries > 0){
maxConnectionRetries--;
[self performSelector:#selector(checkInternet:) withObject:block afterDelay:1.0];
}
else{
maxConnectionRetries = 0;
block([(NSHTTPURLResponse *)response statusCode] == 200);
}
}];
}
For general detection of internet connectivity, it is best to use Reachability. See here.
I start a reachability handler from my AppDelegate code and then publish local notifications when connectivity changes occur. This allows the application to always receive connection change notification and transient view controllers within viewWillAppear and viewWillDisappear to register and deregister for local notifications if they are interested in connection changes.
FYI here is what I came up with:
+ (void)checkInternet:(connection)block withMaxTries:(NSUInteger)maxTries
{
NSURL *url = [NSURL URLWithString:#"http://www.google.com/"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = #"HEAD";
request.cachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
request.timeoutInterval = 10.0;
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *connectionError)
{
if ([(NSHTTPURLResponse *)response statusCode] != 200 &&
maxTries > 0){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self checkInternet:block withMaxTries:maxTries - 1];
});
}
else{
block([(NSHTTPURLResponse *)response statusCode] == 200);
}
}];
}

Most efficient way to check flag on server

I'm looking to set up a flag on a webserver, just so that I can change something after I release my app to the app store in case a bug doesn't go away. I'm not familiar with network connections, but I've put together the following:
- (void) loadThumbnailFlag
{
NSURL *url = [NSURL URLWithString:#"http://www.myappsite.com/ThumbnailFlag"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ([httpResponse statusCode] / 100 == 2)
{
self.thumbnailFlag = YES;
}
else
{
self.thumbnailFlag = NO;
}
}
Is there anyway to improve this code so it's not wasting any steps as just to check if the flag exists or not (i.e. it's not trying to download a file or anything).
If you don't need the body, only the response, then it's best to either set the request to type HEAD ([request setHTTPMethod:#"HEAD"]; create an instance of NSMutableURLRequest), or to call cancel on the connection in connection:didReceiveResponse:.
If the server doesn't actually return any body data then it won't make a big difference, but it makes your intentions for the connection clear.

Resources