iOS/iPhone 可达性 - 如何使用 Reachability.m/.h 仅检查互联网何时丢失/无法访问
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4772173/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS/iPhone Reachability - How to only check when internet is lost/not reachable using Reachability.m/.h
提问by Mausimo
Currently i am using the class by apple reachability.m/.h and it works, except it notifies me for any change, where as i would like to only notify the user if the network is not reachable. Currently if i have a internet connection and then loose the network it tells me. However when you reconnect to the network it also tells me, which i do not want. I want it to only tell me when there is a loss/no network.
目前我正在使用 applereachability.m/.h 的类,它可以工作,但它会通知我任何更改,因为我只想在无法访问网络时通知用户。目前,如果我有互联网连接,然后失去网络,它会告诉我。但是,当您重新连接到网络时,它也会告诉我,这是我不想要的。我希望它只在丢失/没有网络时告诉我。
I believe it has something to do with the call:
我相信这与电话有关:
- (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
}
when calling -[NSNotificationCenter addObserver:selector:name:object:]
, does the name have any other function then being literally a name? this is my first time using NSNotificationCenter so i am not well versed in this matter.
调用时-[NSNotificationCenter addObserver:selector:name:object:]
,该名称是否具有任何其他功能,然后才是真正的名称?这是我第一次使用 NSNotificationCenter,所以我不太了解这个问题。
EDIT:
编辑:
Here is my checkNetworkStatus function: (The problem is i am getting "NotReachable" as the network connection is coming back and NSAlert goes off multiple times)
这是我的 checkNetworkStatus 函数:(问题是当网络连接恢复并且 NSAlert 多次关闭时,我得到了“NotReachable”)
- (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;
}
}
}
}
回答by Brian
Reachability will send a notification when the status has changed, but what you do with that notification is entirely up to you. If you don't want to tell the user that the network is back, you don't have to.
当状态发生变化时,可达性将发送通知,但您如何处理该通知完全取决于您。如果您不想告诉用户网络已恢复,则不必这样做。
The "name" parameter in the NSNotificationCenter method indicates what notification you are subscribing to. When an object posts a notification, it does so with a particular name.
NSNotificationCenter 方法中的“name”参数指示您订阅的通知。当一个对象发布通知时,它会使用一个特定的名称。
回答by ddavtian
If you replace the www.hostname.com with just an IP address, it will only alert once instead of multiple times.
如果你只用一个 IP 地址替换 www.hostname.com,它只会提醒一次而不是多次。
回答by smoothdvd
With Reachability 2.2, you can add
使用 Reachability 2.2,您可以添加
[hostReach connectionRequired];
before
前
[internetReachable startNotifier];
to solve this problem.
来解决这个问题。
runmadanswered this problem here: https://stackoverflow.com/a/2157858/623260
runmad在这里回答了这个问题:https: //stackoverflow.com/a/2157858/623260
回答by yjw
I just started playing around with Reachability and hopefully what I discovered is of use to you.
我刚开始玩 Reachability,希望我发现的东西对你有用。
With regards to multiple 'Not Reachable' while reconnecting, could it be linked to this? Here the poster brought up the definition of 'reachable' for a remote host. I'm guessing while reconnecting the package is not able to go through successfully?
关于重新连接时出现的多个“无法访问”,是否与此相关?在这里,海报提出了远程主机“可达”的定义。我猜重新连接包时无法成功通过?
Another possibility is in Reachability Readme.txt
另一种可能性是在 Reachability Readme.txt
IMPORTANT: Reachability must use DNS to resolve the host name before it can determine the Reachability of that host, and this may take time on certain network connections. Because of this, the API will return NotReachable until name resolution has completed. This delay may be visible in the interface on some networks.
重要信息:可达性必须使用 DNS 来解析主机名,然后才能确定该主机的可达性,这在某些网络连接上可能需要一些时间。因此,在名称解析完成之前,API 将返回 NotReachable。在某些网络的界面中可能会看到此延迟。
Maybe give it the IP directly and see if it helps?
也许直接给它IP,看看它是否有帮助?
回答by danh
One thing you can do is unsubscribe to the changed notification NSNotificationCenter removeObserver... while you're processing one in the callback. Add back the observer before returning.
您可以做的一件事是取消订阅已更改的通知 NSNotificationCenter removeObserver... 当您在回调中处理通知时。在返回之前添加回观察者。
回答by W Dyson
I would implement the whole Reachability class, tie it into your code as necessary and remove or comment out parts of Reachability. Just remove, one by one, the things you do not want to be notified of. Obviously, you need a good understanding of obj-c, the Reachability class, notifications, etc., but it can be done.
我会实现整个 Reachability 类,根据需要将其绑定到您的代码中,并删除或注释掉 Reachability 的部分内容。只需将您不想被通知的事情一一删除。很明显,你需要对 obj-c、Reachability 类、通知等有很好的理解,但这是可以做到的。
回答by sinh99
We can check rechability using this code
我们可以使用此代码检查可恢复性
add class Reachability.h
添加类 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
可达性.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
and use via direct calling method in appdel class using
并通过 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;
}
}
}