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);
}];
}
Related
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);
}
}];
}
Today, I was testing the reachabilityWithHostName, and I'm typing a domain that is timing out inside the network that I'm joined, but the reachability its returning as its there a connection.
Why is might this be occurring?
Thanks
Here is my ping log:
PING 188.121.62.144 (188.121.62.144): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
Request timeout for icmp_seq 4
Request timeout for icmp_seq 5
Request timeout for icmp_seq 6
Here is my code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
Reachability* reachability = [Reachability reachabilityWithHostName:#"188.121.62.144"];
NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus];
if(remoteHostStatus == NotReachable)
{
isInternet = NO;
}
else if (remoteHostStatus == ReachableViaWWAN)
{
isInternet = TRUE;
}
else if (remoteHostStatus == ReachableViaWiFi)
{
isInternet = TRUE;
}
if (!isInternet)
{
NSLog(#"No connection");
}
else
{
NSLog(#"There is connection");
}
return YES;
}
Can you try to ping with the below modified code .
Reachability* reachability = [Reachability reachabilityWithHostName:#"http://188.121.62.144"];
The Reachability class and -reachabilityWithHostname: is designed to be a quick, fail-fast mechanism to determine whether you have basic network connectivity to the host. If you need to verify that a particular URL can be downloaded, you need to be looking at using NSURLConnection to retrieve the contents of the URL in order to verify that it is truly available.
Depending on whether you need to do this in the foreground or background, you can either use the simple-but-blocking:
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
or you can use the more complicated method of creating an NSURLConnection object, setting up a delegate to receive responses and wait for those responses to come in.
For the simple case:
NSURL *myURL = [NSURL urlWithString: #"http://188.121.62.144"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: myURL];
[request setHTTPMethod: #"HEAD"];
NSURLResponse *response;
NSError *error;
NSData *myData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
If you receive back a non-nil myData, you've got some kind of connectivity. response and error will tell you what the server responded to you (in the case of response and if you received a non-nil myData) or what kind of error occurred, in the case of a nil myData.
For the non-trivial case, you can get good guidance from Apple's Using NSURLConnection.
If you don't want to stall your foreground process, you can do this two different ways. The above documentation will provide information on how to implement the delegate, etc. However, a simpler implementation would be to use GCD to send the Synchronous request on a background thread, and then message yourself on the main thread when you are done.
Something like this:
NSURL *myURL = [NSURL urlWithString: #"http://188.121.62.144"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: myURL];
[request setHTTPMethod: #"HEAD"];
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, NULL), ^{
NSURLResponse *response;
NSError *error;
NSData *myData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
BOOL reachable;
if (myData) {
// we are probably reachable, check the response
reachable=YES;
} else {
// we are probably not reachable, check the error:
reachable=NO;
}
// now call ourselves back on the main thread
dispatch_async( dispatch_get_main_queue(), ^{
[self setReachability: reachable];
});
});
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.
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 :-)
I am aware of discussions regarding nsurlconnection on ios, and that there is a minimum of 240 seconds for a timeout. My question is, if I am sending a synchronous call via NSURLConnection's + (NSData *)sendSynchronousRequest:(NSURLRequest )request returningResponse:(NSURLResponse *)response error:(NSError **)error, is there any chance I can cancel this before the 240 seconds is up? I am thinking perhaps setting a timer to cancel this synchronous request, but im not even sure if its even possible? Im thinking:
[self performSelector:#selector(cancelRequest:) withObject:myRequest afterDelay:myTimeOut];
I have a feeling this will result in disaster if somehow the request has been released, and I would have no way to determine that. Thoughts? Has anyone tried to do this? This is a synchronous call.
You cannot cancel it. Simply don't use it and use an asynchronous call instead. Those you can easily cancel.
This seemed to work for me:
NSURL *url = [NSURL URLWithString:#"http://someurl.com"];
NSURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5];
NSHTTPURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
if (response == nil) {
// timed out or failed
} else {
// all good
}
Ofcourse setting the timeout interval to how long you want it to block the main thread before timing out - The above code successfully timed out after 5 seconds
Tested in iOS6 & iOS5.1
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
webData = (NSMutableData *)[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
if (webData==nil) {
[self displayAlert:#"Time Out" message:#"Request Timed Out"];
}
Timeout in exactly 10 seconds.