Доступность для iOS / iPhone - Как проверить, только когда Интернет потерян / недоступен, используя Reachability.m / .h - PullRequest
10 голосов
/ 23 января 2011

В настоящее время я использую класс by 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 ]

5 голосов
/ 23 января 2011

Reachability отправит уведомление, когда статус изменится, но что вы делаете с этим уведомлением, полностью зависит от вас. Если вы не хотите сообщать пользователю, что сеть вернулась, вам не нужно.

Параметр «name» в методе NSNotificationCenter указывает, на какое уведомление вы подписаны. Когда объект публикует уведомление, он делает это с определенным именем.

2 голосов
/ 25 мая 2012

Если вы замените www.hostname.com просто IP-адресом, он будет предупреждать только один раз, а не несколько раз.

1 голос
/ 19 февраля 2012

С помощью Reachability 2.2 вы можете добавить

[hostReach connectionRequired];

до

[internetReachable startNotifier];

чтобы решить эту проблему.

runmad ответил на эту проблему здесь: https://stackoverflow.com/a/2157858/623260

1 голос
/ 12 июня 2011

Я только начал играть с Reachability, и надеюсь, что то, что я обнаружил, пригодится вам.

Что касается нескольких «Недостижимых» при повторном подключении, может ли это быть связано с этим ? Здесь автор поднял определение «достижимости» для удаленного хоста. Я предполагаю, что при повторном подключении пакет не может пройти успешно?

Еще одна возможность в Reachability Readme.txt

ВАЖНО: Reachability должен использовать DNS для разрешения имени хоста до него может определить доступность этого хоста, и это может занять некоторое время определенные сетевые подключения. Из-за этого API вернется NotReachable, пока разрешение имени не будет завершено. Эта задержка может быть видна в интерфейсе в некоторых сетях.

Может быть, дать ему IP напрямую и посмотреть, поможет ли это?

0 голосов
/ 26 октября 2012

Мы можем проверить rechability с помощью этого кода

добавить класс 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;
    }
 }
}
0 голосов
/ 28 января 2012

Одна вещь, которую вы можете сделать, это отменить подписку на измененное уведомление NSNotificationCenter removeObserver ... пока вы обрабатываете одно в обратном вызове. Добавьте обратно наблюдателя, прежде чем вернуться.

0 голосов
/ 23 января 2011

Я бы реализовал весь класс Reachability, связал бы его с вашим кодом по мере необходимости и удалил или закомментировал части Reachability. Просто удалите одну за другой вещи, о которых вы не хотите получать уведомления. Очевидно, вам нужно хорошее понимание obj-c, класса Reachability, уведомлений и т. Д., Но это можно сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...