Reputation: 1484
I have an app that allow automatic login for a user. What my boss want is, when the app launches, the app need to test connectivity to our server (not just test whether there is WiFi or 3G network). I borrowed apple's Reachability sample, it works.
A problem is that takes too long, especially at the launch time. I tried it on a local wireless network without internet connection, it took me almost half an minute to do so. And since auto login called in -ViewDidLoad(), for that half minute, ui didn't load. It is just simply not acceptable to take the time that long. What's even worse, if my app takes too long to load, iOS might even shut the app down.
Further more, I have a lot of web service calls in my app. I understand each web service call could have the chance to fail, because the nature that iPhone/iPad can lose or gain connection easily even when user talk a short walk from one place to another. I personally don't like it but that's what my boss want me to do, and I probably have to test the connection quite often in the app.
So here what I am looking for is either a way to detect connection really really fast(within seconds) or a way to do it behind the scenes and not effect user experience.
Anybody has suggestions?
Thank you for taking your time reading my questions.
Upvotes: 4
Views: 4901
Reputation:
As I told in the comments you should use Hampus Nilsson's approach to perform the request in the background anyways.
Regarding to your 30 seconds problem I found this in another blog:
- (BOOL)isHostAvailable:(NSString*)hostName
{
// this should check the host but does not work in the simulator, aka it returns YES when should be no
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName cStringUsingEncoding:NSASCIIStringEncoding]);
SCNetworkReachabilityFlags flags;
BOOL success = SCNetworkReachabilityGetFlags(reachability, &flags);
if (reachability) {
CFRelease(reachability);
}
if ( ( success && (flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired) ) == NO) {
return NO;
}
// we know at least the network is up, second check for a known page
NSData *dataReply;
NSURLResponse *response;
NSError *error;
// create the request
NSString *urlString = [NSString stringWithFormat:@"http://%@/index.php", hostName];
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:8.0];
// Make the connection
dataReply = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&response error:&error];
if (response != nil) {
NSLog(@"SNNetworkController.isHostAvailable %@", response);
return YES;
} else {
// inform the user that the download could not be made
NSLog(@"SNNetworkController.isHostAvailable %@ %@", response, error);
return NO;
}
}
this will perform a request with a timeout value of 8 seconds.
//EDIT:
ASIHTTPRequest
example:
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setNumberOfTimesToRetryOnTimeout:3];
[request setTimeOutSeconds:20.0];
[request setRequestMethod:@"POST"];
[request startAsynchronous];
Upvotes: 4
Reputation: 2153
For what it's worth, here is the method I use..
- (BOOL)checkServerAvailability {
bool success = false;
const char *host_name = [@"host" cStringUsingEncoding:NSASCIIStringEncoding];
SCNetworkReachabilityRef reachability =
SCNetworkReachabilityCreateWithName(NULL, host_name);
SCNetworkReachabilityFlags flags;
success = SCNetworkReachabilityGetFlags(reachability, &flags);
bool isAvailable = success && (flags & kSCNetworkFlagsReachable)
&& !(flags & kSCNetworkFlagsConnectionRequired);
CFRelease(reachability);
return isAvailable;
}
Here is the logging result of my server check method...
2012-07-11 11:29:04.892 ASURecycles[1509:f803] starting server check...
2012-07-11 11:29:04.894 ASURecycles[1509:f803] creating reachability...
2012-07-11 11:29:04.894 ASURecycles[1509:f803] creating flags...
2012-07-11 11:29:04.913 ASURecycles[1509:f803] checking for success of reachability, assigning to flags..
2012-07-11 11:29:04.913 ASURecycles[1509:f803] checking our flags to determine network status...
2012-07-11 11:29:04.913 ASURecycles[1509:f803] not available
As you can see, fractions of a second. Of course our server is undergoing trouble at the moment, but I think your issue may be a server issue, not a framework issue. You could always try executing the server check on another thread though.
Upvotes: 5
Reputation: 6822
Present an intermediate loading view with presentModalViewController
while the test is taking place and run the actual test using performSelectorInBackground
. Then signal back to the main thread with performSelectorOnMainThread
:
- (void)viewDidLoad
{
[super viewDidLoad];
// Make this a hidden member
loadingViewController = [LoadingViewController new];
[self presentModalViewController:loadingViewController animated:NO];
[self performSelectorInBackground:@selector(testConnectivity) withObject:nil];
}
- (void)testConnectivity
{
// Do expensive testing stuff
[self performSelectorOnMainThread:@selector(testCompleted) withObject:nil waitUntilDone:NO];
}
- (void)testCompleted
{
[loadingViewController dismissViewControllerAnimated:YES];
loadingViewController = nil;
}
Note that the overall user experience of waiting 30 seconds for the application to start sort of sucks, and connectivity often changing while you are using an app, so even if you do the test every startup it's unlikely to be reliable. But if it is what your boss wants I suffer with you. ;)
Upvotes: 5