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.
Related
I check internet connection following way.
in viewDidload
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
then
- (BOOL)connected {
return [AFNetworkReachabilityManager sharedManager].reachable;
}
But even if i don't have internet connection but 3g is on, it still returns true.
How can i detect if the real internet connection exists?
Reachability being true doesn't mean that the next network access you do will succeed -- you need to assume that network access can always fail.
It's good at letting you know the user has turned off network access (like Airplane mode), but if you are on a bad network, dropping lots of packets, then Reachability will still return true. It should also detect if you can't get any Wifi or 3G at all. But, if you have one bar -- it's going to return true, even if that means that network access won't really work.
I did it this way. I know it's no elegant, but...
+ (void)checkInternet:(connection)block
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
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)
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
block([(NSHTTPURLResponse *)response statusCode] == 200);
}];
}
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
}
}
i have this method
- (BOOL)connectedToInternet
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:#"http://www.google.com/"]];
[request setHTTPMethod:#"HEAD"];
NSHTTPURLResponse *response;
[NSURLConnection sendSynchronousRequest:request
returningResponse:&response error: NULL];
return ([response statusCode] == 200) ? YES : NO;
}
that method is taking a few seconds to do it, im using it in a simple if conditional to know if i have internet connection.
is there any way to do it in a background thread without having to change all code.
I'm calling it this way
if([self connectedToInternet])
So if i do it in a background thread i cant get the return value and then my method cant return the value.
If i have to change all it doesn't worth it.
I hope u can understand my question and thanks for any help.
In Apple's "Reachability" Code Sample note the reachabilityWithAddress: method please.
You can do something similar to this using blocks;
definition (.h)
+ (void)isConnectedToInternet:(void (^)(BOOL connected))block;
implementation (.m)
+ (void)isConnectedToInternet:(void (^)(BOOL))block
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:#"http://www.google.com/"]];
[request setHTTPMethod:#"HEAD"];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
if (block) {
block( ([httpResponse statusCode] == 200) ? YES : NO);
}
}];
}
then call it like
[MyClass isConnectedToInternet:^(BOOL connected) {
if (connected) {
// do stuff;
}
}];
I don't know what exactly what you want to do, but what you want to use is probably :
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
//your asynchronous code here
});
But by using an if condition, you need the result in order to continue, don't you? So why running the code in background?
I would suggest the method which you are implementing to know 'if Internet is connected or not' is not the most optimized one... few days back I also tried to implement the same thing.. and I came across couple of solutions, over Internet.. and I wrote about it on my blog.. Checking Internet connection in cocoa.
My preferred way to know if network is connected or not is by using Reachability class. You can get clue on using it from this code: NetworkCheckUtility.
Hope this helps :-)
Our requirements include checking Internet access to a specific file on the web-server. This file is checked every n minutes. NSURLRequests never calls connection:didFailWithError whether or not there is an internet connection. And the HTTP status is always 200. Apple's reachibility only works for domains, not files- so it doesn't meet the requirements. How can I reliably discover if I can reach this file every n minutes? Why isn't the http status code really the http status code?
Other stackoverflow questions that would seem to answer this question do not work:
1. How could connectionDidFinishLoading: run if no file is found on server?
2. Testing use of NSURLConnection with HTTP response error statuses
I tried using another queue with a completion block, but that also didn't work.
-(void) updateConnectionStatus
{
NSURL *url = [NSURL URLWithString:(NSString*)[appValues getValueForSettingsKey:#"company.project.test.pingURL"]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
//NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//__block __typeof__(self) _self = self;
connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
/*
[NSURLConnection
sendAsynchronousRequest:urlRequest queue:queue
completionHandler:^(NSURLResponse *response,
NSData *data,
NSError *error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
int code = [httpResponse statusCode]; // ALWAYS 200 no matter what
NSString *pingFile = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#",error); // NEVER has an error
//This doesn't even work because it remembers FOREVER the value once it gets it.
if ([#"Ping!" isEqualToString:pingFile])
{
dispatch_async(dispatch_get_main_queue(), ^{
[_self companyConnection:YES];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[_self companyConnection:NO];
});
}
}];
*/
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"ERROR: %#", error); // Never get here
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse *aResponse = (NSHTTPURLResponse*)response;
NSLog(#"received a response: %ld",(long)[aResponse statusCode] );
if ([response respondsToSelector:#selector(statusCode)])
{
int statusCode = [((NSHTTPURLResponse *)response) statusCode];
// statusCode is always 200
if (statusCode >= 400)
{
[companyConnection cancel]; // stop connecting; no more delegate messages
NSDictionary *errorInfo
= [NSDictionary dictionaryWithObject:[NSString stringWithFormat:
NSLocalizedString(#"Server returned status code %d",#""),
statusCode]
forKey:NSLocalizedDescriptionKey];
}
}
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"received data");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Finished");
}
Try with setting cachePolicy as NSURLRequestReloadIgnoringCacheData while constructing the NSURLRequest object
Thanks to Wain and Rob for putting me onto the right path. One way to keep the cache clear is adding this method to your NSURLConnectionDelegate:
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}
The purpose of my code is to compare the modification dates of a server file and a local file, in case that the server file is newer, it will download it.
My first attempt was to use a synchronous request using the code from http://iphoneincubator.com/blog/server-communication/how-to-download-a-file-only-if-it-has-been-updated
But it didn't worked.
After that I've been struggling to find the solution, tried asynchronous request, tried different codes I found around stackoverflow, google, etc. but nothing works.
If in terminal I do curl -I <url-to-file> I get the header values so I know is not a server problem.
This is the code I'm struggling with right now (It's written in Appdelegate.m)
- (void)downloadFileIfUpdated {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval: 10];
[request setHTTPMethod:#"HEAD"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
if(!connection) {
NSLog(#"connection failed");
} else {
NSLog(#"connection succeeded");
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self downloadFileIfUpdated]
}
#pragma mark NSURLConnection delegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSString *lastModifiedString = nil;
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
if ([response respondsToSelector:#selector(allHeaderFields)]) {
lastModifiedString = [[response allHeaderFields] objectForKey:#"Last-Modified"];
}
[Here is where the formatting-date-code and downloading would take place]
}
Right now, as it is, it gives me the error No visible #interface for 'NSURLResponse' declares de selector 'allHeaderFields'.
When I use the synchronous approach the error is that NSLog(#"%#",lastModifiedString)returns (null).
PS: If there is a better way I can explain myself or the code, please let me know.
UPDATE
The URL I'm using is of type ftp://and that may be the problem of why I don't get any HEADERS. But I can't figure out how to do it then.
Change your code to this... in the 'if' conditional, you were checking response instead of httpResponse:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSString *lastModifiedString = nil;
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
if ([httpResponse respondsToSelector:#selector(allHeaderFields)]) {
lastModifiedString = [[httpResponse allHeaderFields] objectForKey:#"Last-Modified"];
}
// [Here is where the formatting-date-code and downloading would take place]
}
... and once you feel comfortable that the response is going to always be an NSHTTPURLResponse, you could probably just get rid of the conditional statement:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSString *lastModifiedString = [[httpResponse allHeaderFields] objectForKey:#"Last-Modified"];
// [Here is where the formatting-date-code and downloading would take place]
}