iOS / iPhone可达性 – 如何使用Reachability.m / .h检查互联网何时丢失/无法访问

目前我正在使用苹果reachability.m / .h类,它的工作原理,除了它通知我的任何改变,因为我只想通知用户,如果networking不可达。 目前,如果我有一个互联网连接,然后松动networking它告诉我。 但是,当你重新连接到networking,它也告诉我,我不想要。 我只想告诉我什么时候有一个损失/没有networking。

我相信这跟电话有关:

- (void)viewWillAppear:(BOOL)animated { // check for internet connection [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil]; internetReachable = [[Reachability reachabilityForInternetConnection] retain]; [internetReachable startNotifier]; // check if a pathway to a random host exists hostReachable = [[Reachability reachabilityWithHostName: @"www.google.ca"] retain]; [hostReachable startNotifier]; // now patiently wait for the notification } 

当调用-[NSNotificationCenter addObserver:selector:name:object:] ,该名称有任何其他function,那么字面上的名字? 这是我第一次使用NSNotificationCenter,所以我不太了解这个问题。

编辑:

这是我的checkNetworkStatus函数:(问题是我越来越“不可接近”,因为networking连接回来和NSAlertclosures多次)

 - (void) checkNetworkStatus:(NSNotification *)notice { // called after network status changes NetworkStatus internetStatus = [internetReachable currentReachabilityStatus]; switch (internetStatus) { case NotReachable: { UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Network Failed" message:@"Please check your connection and try again." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil ]; [alert show]; NSLog(@"The internet is down."); break; } case ReachableViaWiFi: { NSLog(@"The internet is working via WIFI."); break; } case ReachableViaWWAN: { NSLog(@"The internet is working via WWAN."); break; } } NetworkStatus hostStatus = [hostReachable currentReachabilityStatus]; switch (hostStatus) { case NotReachable: { NSLog(@"A gateway to the host server is down."); break; } case ReachableViaWiFi: { NSLog(@"A gateway to the host server is working via WIFI."); break; } case ReachableViaWWAN: { NSLog(@"A gateway to the host server is working via WWAN."); break; } } 

}

可达性将在状态发生变化时发送通知,但是您对该通知的处理完全取决于您。 如果你不想告诉用户networking回来,你不需要。

NSNotificationCenter方法中的“name”参数指示您正在订阅哪个通知。 当一个对象发布通知时,它会使用特定的名称。

如果将www.hostname.comreplace为IP地址,则只会提示一次而不是多次。

我刚开始玩Reachability,希望我发现对你有用。

关于重新连接时的多个“不可达”,是否可以链接到这个 ? 这里海报提出了远程主机的“可达”定义。 我猜测重新连接包是无法成功通过?

另一种可能性是在Reachability Readme.txt中

重要提示:可达性必须先使用DNS来parsing主机名称,然后才能确定该主机的可达性,并且这可能需要一段时间才能完成某些networking连接。 因此,在名称parsing完成之前,API将返回NotReachable。 这种延迟可能在某些networking的接口中可见。

也许直接给它的IP,看看是否有帮助?

随着可达性2.2,你可以添加

 [hostReach connectionRequired]; 

之前

 [internetReachable startNotifier]; 

解决这个问题。

runmad在这里回答了这个问题: https : //stackoverflow.com/a/2157858/623260

我将实现整个Reachability类,根据需要将其绑定到代码中,并删除或注释Reachability的某些部分。 只要一个一个地删除你不想被通知的事情。 显然,你需要对obj-c,Reachability类,通知等有一个很好的理解,但是可以这样做。

你可以做的一件事是取消订阅更改的通知NSNotificationCenter removeObserver …当你在callback中处理一个。 在返回之前添加观察者。

我们可以使用这个代码来检查可重用性

添加Reachability.h类

 #import <Foundation/Foundation.h> #import <SystemConfiguration/SystemConfiguration.h> typedef enum { NotReachable = 0, ReachableViaWiFi, ReachableViaWWAN } NetworkStatus; #define kReachabilityChangedNotification @"kNetworkReachabilityChangedNotification" @interface Reachability: NSObject { BOOL localWiFiRef; SCNetworkReachabilityRef reachabilityRef; } //reachabilityWithHostName- Use to check the reachability of a particular host name. + (Reachability*) reachabilityWithHostName: (NSString*) hostName; //reachabilityWithAddress- Use to check the reachability of a particular IP address. + (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress; //reachabilityForInternetConnection- checks whether the default route is available. // Should be used by applications that do not connect to a particular host + (Reachability*) reachabilityForInternetConnection; //reachabilityForLocalWiFi- checks whether a local wifi connection is available. + (Reachability*) reachabilityForLocalWiFi; //Start listening for reachability notifications on the current run loop - (BOOL) startNotifier; - (void) stopNotifier; - (NetworkStatus) currentReachabilityStatus; //WWAN may be available, but not active until a connection has been established. //WiFi may require a connection for VPN on Demand. - (BOOL) connectionRequired; @end 

Reachability.m

 #import <sys/socket.h> #import <netinet/in.h> #import <netinet6/in6.h> #import <arpa/inet.h> #import <ifaddrs.h> #import <netdb.h> #import <CoreFoundation/CoreFoundation.h> #import "Reachability.h" #define kShouldPrintReachabilityFlags 1 static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment) { #if kShouldPrintReachabilityFlags NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n", (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-', comment ); #endif } @implementation Reachability static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) { #pragma unused (target, flags) NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback"); //We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively // in case someon uses the Reachablity object in a different thread. NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init]; Reachability* noteObject = (Reachability*) info; // Post a notification to notify the client that the network reachability changed. [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject]; [myPool release]; } - (BOOL) startNotifier { BOOL retVal = NO; SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL}; if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) { if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { retVal = YES; } } return retVal; } - (void) stopNotifier { if(reachabilityRef!= NULL) { SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); } } - (void) dealloc { [self stopNotifier]; if(reachabilityRef!= NULL) { CFRelease(reachabilityRef); } [super dealloc]; } + (Reachability*) reachabilityWithHostName: (NSString*) hostName; { Reachability* retVal = NULL; SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); if(reachability!= NULL) { retVal= [[[self alloc] init] autorelease]; if(retVal!= NULL) { retVal->reachabilityRef = reachability; retVal->localWiFiRef = NO; } } return retVal; } + (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress; { SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); Reachability* retVal = NULL; if(reachability!= NULL) { retVal= [[[self alloc] init] autorelease]; if(retVal!= NULL) { retVal->reachabilityRef = reachability; retVal->localWiFiRef = NO; } } return retVal; } + (Reachability*) reachabilityForInternetConnection; { struct sockaddr_in zeroAddress; bzero(&zeroAddress, sizeof(zeroAddress)); zeroAddress.sin_len = sizeof(zeroAddress); zeroAddress.sin_family = AF_INET; return [self reachabilityWithAddress: &zeroAddress]; } + (Reachability*) reachabilityForLocalWiFi; { struct sockaddr_in localWifiAddress; bzero(&localWifiAddress, sizeof(localWifiAddress)); localWifiAddress.sin_len = sizeof(localWifiAddress); localWifiAddress.sin_family = AF_INET; // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0 localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress]; if(retVal!= NULL) { retVal->localWiFiRef = YES; } return retVal; } #pragma mark Network Flag Handling - (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags { PrintReachabilityFlags(flags, "localWiFiStatusForFlags"); BOOL retVal = NotReachable; if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) { retVal = ReachableViaWiFi; } return retVal; } - (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags { PrintReachabilityFlags(flags, "networkStatusForFlags"); if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) { // if target host is not reachable return NotReachable; } BOOL retVal = NotReachable; 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 retVal = ReachableViaWiFi; } 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 retVal = ReachableViaWiFi; } } if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) { // ... but WWAN connections are OK if the calling application // is using the CFNetwork (CFSocketStream?) APIs. retVal = ReachableViaWWAN; } return retVal; } - (BOOL) connectionRequired; { NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); SCNetworkReachabilityFlags flags; if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { return (flags & kSCNetworkReachabilityFlagsConnectionRequired); } return NO; } - (NetworkStatus) currentReachabilityStatus { NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef"); NetworkStatus retVal = NotReachable; SCNetworkReachabilityFlags flags; if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) { if(localWiFiRef) { retVal = [self localWiFiStatusForFlags: flags]; } else { retVal = [self networkStatusForFlags: flags]; } } return retVal; } @end 

并在appdel类中使用直接调用方法使用

  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil]; -(void) checkNetworkStatus:(NSNotification *)notice { Reachability* internetReachable; BOOL isInternetActive; // called after network status changes NetworkStatus internetStatus = [internetReachable currentReachabilityStatus]; switch (internetStatus) { case NotReachable: { NSLog(@"The internet is down."); isInternetActive = NO; break; } case ReachableViaWiFi: { NSLog(@"The internet is working via WIFI."); isInternetActive = YES; break; } case ReachableViaWWAN: { NSLog(@"The internet is working via WWAN."); isInternetActive = YES; break; } } NetworkStatus hostStatus = [hostReachable currentReachabilityStatus]; switch (hostStatus) { case NotReachable: { NSLog(@"A gateway to the host server is down."); // self.hostActive = NO; break; } case ReachableViaWiFi: { NSLog(@"A gateway to the host server is working via WIFI."); // self.hostActive = YES; break; } case ReachableViaWWAN: { NSLog(@"A gateway to the host server is working via WWAN."); // self.hostActive = YES; break; } } }