使用iOS SDK检查Internet连接

13

如何使用iOS SDK检查Internet连接的最佳方法是什么?

3个回答

36

最好的方法是使用Reachability代码。请查看苹果的示例代码这里。它具有许多便捷方法,可检查互联网可用性、Wifi / WAN连接等。

例如:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkChanged:) name:kReachabilityChangedNotification object:nil];

reachability = [Reachability reachabilityForInternetConnection];
[reachability startNotifier];

- (void)networkChanged:(NSNotification *)notification
{

  NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus];

  if(remoteHostStatus == NotReachable) { NSLog(@"not reachable");}
  else if (remoteHostStatus == ReachableViaWiFiNetwork) { NSLog(@"wifi"); }
  else if (remoteHostStatus == ReachableViaCarrierDataNetwork) { NSLog(@"carrier"); }
}

1
ReachableViaCarrierDataNetworkReachableViaWiFiNetwork不可用,状态可以是ReachableViaWWANReachableViaWiFi - Hemang
只有在通知后才显示,但需要在网络更改之前显示。如何在viewdidload方法调用时获取可用的网络。 - Bala

13

与其所需相比,可达性功能要多得多,而且它目前还没有更新为ARC。

以下是我用纯C编写的解决方案。其中很多代码直接来自于Reachability,但被简化成只包含必要的部分。我只想让它返回是否有互联网连接,但您可以从注释中读取它是基于找到Wifi还是蜂窝网络来返回YES。

在分享代码之前,最后一个注意事项:您需要进入构建目标,选择“生成阶段”选项卡,并将“SystemConfiguration.framework”添加到“链接二进制文件和库”列表中。

#import <CoreFoundation/CoreFoundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <netdb.h>

BOOL networkReachable()
{
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;

    SCNetworkReachabilityRef reachabilityRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *) &zeroAddress);

    SCNetworkReachabilityFlags flags;
    if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
        if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) {
            // if target host is not reachable
            return NO;
        }

        if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) {
            // if target host is reachable and no connection is required
            //  then we'll assume (for now) that your on Wi-Fi
            return YES; // This is a wifi connection.
        }


        if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0)
            ||(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) {
            // ... and the connection is on-demand (or on-traffic) if the
            //     calling application is using the CFSocketStream or higher APIs

            if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) {
                // ... and no [user] intervention is needed
                return YES; // This is a wifi connection.
            }
        }

        if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) {
            // ... but WWAN connections are OK if the calling application
            //     is using the CFNetwork (CFSocketStream?) APIs.
            return YES; // This is a cellular connection.
        }
    }

    return NO;
}

我非常喜欢你的解决方案,但是个人认为需要进行一些小修改。我认为,你应该返回一个常量或枚举元素,而不是返回BOOL,这样我们就可以确定是否有连接以及连接类型。幸运的是,这个修改并不难做! - Andy Ibanez
1
我相信我在这里犯了一个错误,导致代码泄漏。SCNetworkReachabilityRef 需要在某个时刻被发送到 CFRelease() 中...最好的方法可能是将 SCNetworkReachabilityGetFlags() 分离出来并储存其值,然后释放 reachability ref ,然后进行 if 检查存储的值。这样,堆中存储的 SCNetworkReachability 占用的内存被释放,但你在那时需要的一切(标志和 SCNetworkReachabilityGetFlags() 的返回值)仍然可以在栈上使用。 - ArtOfWarfare

10

尝试这段代码:

- (BOOL)connectedToInternet
{
   NSURL *url=[NSURL URLWithString:@"http://www.google.com"];
   NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
   [request setHTTPMethod:@"HEAD"];
   NSHTTPURLResponse *response;
   [NSURLConnection sendSynchronousRequest:request returningResponse:&response error: NULL];

   return ([response statusCode]==200)?YES:NO;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接