4

我有一个允许用户自动登录的应用程序。我老板想要的是,当应用程序启动时,应用程序需要测试与我们服务器的连接(不仅仅是测试是否有 WiFi 或 3G 网络)。我借了苹果的可达性样本,它有效。

一个问题是耗时太长,尤其是在启动时。我在没有互联网连接的本地无线网络上尝试了它,花了我将近半分钟的时间。由于在 -ViewDidLoad() 中调用了自动登录,因此在那半分钟内,ui 没有加载。花那么长时间是不可接受的。更糟糕的是,如果我的应用加载时间过长,iOS 甚至可能会关闭应用。

此外,我的应用程序中有很多 Web 服务调用。我知道每个 Web 服务调用都有可能失败,因为即使用户从一个地方到另一个地方走一小段路,iPhone/iPad 也很容易失去或获得连接。我个人不喜欢它,但这是我老板要我做的,我可能必须经常在应用程序中测试连接。

因此,我在这里寻找的是一种非常快速(在几秒钟内)检测连接的方法,或者是一种在幕后进行而不影响用户体验的方法。

有人有建议吗?

感谢您花时间阅读我的问题。

4

3 回答 3

5

对于它的价值,这是我使用的方法..

- (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;
}

这是我的服务器检查方法的记录结果...

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

如您所见,只有几分之一秒。当然我们的服务器目前正在遇到问题,但我认为您的问题可能是服务器问题,而不是框架问题。不过,您总是可以尝试在另一个线程上执行服务器检查。

于 2012-07-11T17:04:17.977 回答
5

presentModalViewController在测试发生时显示中间加载视图,并使用performSelectorInBackground. 然后使用以下信号返回主线程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;
}

请注意,等待 30 秒等待应用程序启动的整体用户体验有点糟糕,并且在您使用应用程序时连接经常发生变化,因此即使您每次启动都进行测试,它也不太可能可靠。但如果这是你老板想要的,我会和你一起受苦。;)

于 2012-07-11T14:35:34.143 回答
4

正如我在评论中所说,无论如何你都应该使用Hampus Nilsson 的方法在后台执行请求。

关于您的 30 秒问题,我在另一个博客中发现了这一点:

- (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;
    }
}

这将执行一个超时值为 8 秒的请求。

//编辑:
ASIHTTPRequest示例:

ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setNumberOfTimesToRetryOnTimeout:3];
[request setTimeOutSeconds:20.0];
[request setRequestMethod:@"POST"];
[request startAsynchronous];
于 2012-07-16T14:22:37.037 回答