2011-01-23 11 views
10

Attualmente sto usando la classe da apple raggiungibilità.m/.h e funziona, tranne che mi notifica per qualsiasi cambiare, dove come vorrei solo informare l'utente se la rete non è raggiungibile. Attualmente se ho una connessione internet e poi mi libero la rete mi dice. Tuttavia, quando ti riconnetti alla rete, mi dice anche che non voglio. Voglio che mi dica solo quando c'è una perdita/nessuna rete.Raggiungibilità iOS/iPhone - Come controllare solo quando Internet è perso/non raggiungibile utilizzando Reachability.m/.h

credo che abbia qualcosa a che fare con la chiamata:

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

quando si chiama -[NSNotificationCenter addObserver:selector:name:object:], si fa il nome hanno alcuna altra funzione che poi sia letteralmente un nome? questa è la prima volta che utilizzo NSNotificationCenter, quindi non sono esperto in questa materia.

EDIT:

Qui è la mia funzione checkNetworkStatus: (Il problema è che sto ottenendo "NotReachable", come la connessione di rete sta tornando e NSAlert va fuori più volte)

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

    } 
} 

}

+0

cosa divertente: Ho appena notato che se l'iPhone è connesso ad AdHoc WiFi (nessuna connessione Internet) il risultato è ancora positivo per la connettività internet via WiFi. –

+0

@rokjarc è per questo che si controlla anche per vedere se l'host è raggiungibile. – Joe

+0

true: in realtà è tutto ciò che devi sapere. Io credo che la nomenclatura sia sbagliata: in una rete AdHoc isolata Internet (o WWW) non è raggiungibile ... ma sto dividendo i capelli qui :) –

risposta

5

Raggiungibilità invierà una notifica quando lo stato è cambiato, ma ciò che si fa con tale notifica è interamente a carico dell'utente. Se non si desidera comunicare all'utente che la rete è tornata, non è necessario.

Il parametro "nome" nel metodo NSNotificationCenter indica a quale notifica si sta effettuando la sottoscrizione. Quando un oggetto invia una notifica, lo fa con un nome particolare.

+0

Per favore vedi la mia modifica – Mausimo

0

Implementare l'intera classe Reachability, legarla nel codice in base alle esigenze e rimuovere o commentare parti di Raggiungibilità. Basta rimuovere, una per una, le cose a cui non vuoi essere avvisato. Ovviamente, è necessaria una buona comprensione di obj-c, della classe Reachability, delle notifiche, ecc., Ma è possibile farlo.

+0

Vedi la mia modifica – Mausimo

+0

The AlertView viene visualizzato più volte perché checkNetworkStatus viene chiamato più volte di seguito. Devi trovare le altre chiamate per quel metodo e rimuoverle in modo che vengano chiamate solo una volta. –

+0

Non capisco, metto solo checkNetworkStatus una volta su NSNotificationCenter ... – Mausimo

1

Ho appena iniziato a giocare con Reachability e spero che ciò che ho scoperto sia utile.

Riguardo al multiplo "Non raggiungibile" durante la riconnessione, potrebbe essere collegato a this? Qui il poster ha portato la definizione di "raggiungibile" per un host remoto. Sto indovinando mentre ricollegare il pacchetto non è in grado di passare con successo?

Un'altra possibilità è in raggiungibilità Readme.txt

IMPORTANTE: raggiungibilità deve utilizzare DNS per risolvere il nome host prima che in grado di determinare la raggiungibilità di che ospitano, e questo può richiedere tempo sul alcune connessioni di rete. Per questo motivo, l'API restituirà NotReachable fino al completamento della risoluzione dei nomi. Questo ritardo può essere visibile nell'interfaccia su alcune reti.

Forse dargli l'IP direttamente e vedere se aiuta?

0

Una cosa che puoi fare è annullare l'iscrizione alla notifica modificata NSNotificationCenter removeObserver ... mentre ne stai elaborando uno nel callback. Aggiungi indietro l'osservatore prima di tornare.

2

Se si sostituisce la www.hostname.com con solo un indirizzo IP, avviserà solo una volta, invece di più volte.

0

Possiamo controllare rechability utilizzando questo codice

classe add 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 

e utilizzare tramite metodo di chiamata diretta in appdel classe utilizzando

[[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

SCNetworkReachabilitySetCallback ha un comportamento apparentemente diverso ora su iOS 8, in cui il callback non viene eseguito fino a qualche secondo e non immediatamente quando la connettività viene interrotta. – cynistersix

Problemi correlati