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

时间:2011-01-23 03:41:28

标签: ios iphone objective-c nsnotificationcenter reachability

目前我正在通过apple reachability.m / .h使用该类,它可以工作,除了它通知我任何更改,我想只通知用户网络是否无法访问。目前,如果我有互联网连接,然后松散网络它告诉我。但是当你重新连接到网络时,它也告诉我,我不想要。我希望它只在有丢失/无网络时告诉我。

我认为这与电话有关:

- (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:]时,该名称是否具有任何其他功能,然后才是名字?这是我第一次使用NSNotificationCenter,所以我不太熟悉这个问题。

编辑:

这是我的checkNetworkStatus功能:(问题是我得到" NotReachable"因为网络连接回来了,NSAlert多次关闭)

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

    }
}

}

7 个答案:

答案 0 :(得分:5)

可更改性会在状态发生变化时发送通知,但您对该通知的处理完全取决于您。如果您不想告诉用户网络已恢复,则您不必这样做。

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

答案 1 :(得分:2)

如果您仅使用IP地址替换www.hostname.com,它只会提醒一次而不是多次。

答案 2 :(得分:1)

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

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

另一种可能性是Reachability Readme.txt

重要信息:可访问性必须使用DNS来解析之前的主机名 可以确定该主机的可达性,这可能需要一段时间 某些网络连接。因此,API将返回 在名称解析完成之前无法访问。这种延迟可能是 在某些网络的界面中可见。

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

答案 3 :(得分:1)

使用Reachability 2.2,您可以添加

[hostReach connectionRequired];

[internetReachable startNotifier];

解决这个问题。

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

答案 4 :(得分:0)

我会实现整个Reachability类,根据需要将其绑定到您的代码中,并删除或注释掉Reachability的部分内容。只需逐个删除您不希望收到通知的内容。显然,你需要对obj-c,Reachability类,通知等有一个很好的理解,但是可以做到。

答案 5 :(得分:0)

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

答案 6 :(得分:0)

我们可以使用此代码检查可达性

添加课程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

使用

在Apple类中使用直接调用方法
  [[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;
    }
 }
}