Created
March 17, 2009 00:08
-
-
Save norio-nomura/80184 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Reachability.h | |
// | |
#import <Foundation/Foundation.h> | |
#import <SystemConfiguration/SystemConfiguration.h> | |
@interface Reachability : NSObject { | |
NSString *hostName; | |
SCNetworkReachabilityFlags reachabilityFlags; | |
SCNetworkReachabilityRef reachabilityRef; | |
CFMutableArrayRef runLoops; | |
} | |
@property (nonatomic,readonly) NSString *hostName; | |
@property (nonatomic) BOOL enableNotification; | |
@property (nonatomic,readonly) NSString *notificationName; | |
@property (nonatomic,readonly) BOOL isReachableWithoutRequiringConnection; | |
@property (nonatomic,readonly) BOOL isReachableWithWWAN; | |
@property (readonly) SCNetworkReachabilityFlags reachabilityFlags; | |
- (id)initWithHostName:(NSString*)aHostName; | |
- (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector; | |
- (void)removeObserver:(id)notificationObserver; | |
@end | |
// | |
// Reachability.m | |
// | |
#import "Reachability.h" | |
@interface Reachability(private) | |
@property (nonatomic,assign) SCNetworkReachabilityFlags reachabilityFlags; | |
- (void)updateReachabilityFlagsIfEnableNotificationIsNo; | |
- (BOOL)isScheduledOnRunLoop:(NSRunLoop *)inRunLoop; | |
- (void)scheduleOnRunLoop:(NSRunLoop *)inRunLoop; | |
- (void)unscheduleFromRunLoop:(NSRunLoop*)inRunLoop; | |
@end | |
@implementation Reachability | |
@synthesize hostName; | |
@synthesize reachabilityFlags; | |
- (void)dealloc { | |
[hostName release]; | |
if (reachabilityRef) { | |
for (CFIndex index = 0; index < CFArrayGetCount(runLoops); index++) { | |
CFRunLoopRef runLoop = (CFRunLoopRef)CFArrayGetValueAtIndex(runLoops, index); | |
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, runLoop, kCFRunLoopDefaultMode); | |
} | |
} | |
CFRelease(reachabilityRef); | |
CFRelease(runLoops); | |
[super dealloc]; | |
} | |
- (void)setEnableNotification:(BOOL)flag { | |
@synchronized(self) { | |
NSRunLoop *mainRunLoop = [NSRunLoop mainRunLoop]; | |
if (!flag && [self isScheduledOnRunLoop:mainRunLoop]) { | |
[self unscheduleFromRunLoop:mainRunLoop]; | |
} else if (flag && ![self isScheduledOnRunLoop:mainRunLoop]) { | |
[self scheduleOnRunLoop:mainRunLoop]; | |
} | |
} | |
} | |
- (BOOL)enableNotification { | |
@synchronized(self) { | |
return [self isScheduledOnRunLoop:[NSRunLoop mainRunLoop]]; | |
} | |
} | |
- (NSString*)notificationName { | |
return [NSString stringWithFormat:@"kNetworkReachabilityChangedNotification(%@)",hostName]; | |
} | |
- (BOOL)isReachableWithoutRequiringConnection { | |
@synchronized(self) { | |
[self updateReachabilityFlagsIfEnableNotificationIsNo]; | |
// kSCNetworkReachabilityFlagsReachable indicates that the specified nodename or address can | |
// be reached using the current network configuration. | |
BOOL isReachable = reachabilityFlags & kSCNetworkReachabilityFlagsReachable; | |
// This flag indicates that the specified nodename or address can | |
// be reached using the current network configuration, but a | |
// connection must first be established. | |
// | |
// If the flag is false, we don't have a connection. But because CFNetwork | |
// automatically attempts to bring up a WWAN connection, if the WWAN reachability | |
// flag is present, a connection is not required. | |
BOOL noConnectionRequired = !(reachabilityFlags & kSCNetworkReachabilityFlagsConnectionRequired); | |
if (reachabilityFlags & kSCNetworkReachabilityFlagsIsWWAN) { | |
noConnectionRequired = YES; | |
} | |
return (isReachable && noConnectionRequired) ? YES : NO; | |
} | |
} | |
- (BOOL)isReachableWithWWAN { | |
@synchronized(self) { | |
[self updateReachabilityFlagsIfEnableNotificationIsNo]; | |
BOOL isReachable = reachabilityFlags & kSCNetworkReachabilityFlagsReachable; | |
BOOL isWWAN = reachabilityFlags & kSCNetworkReachabilityFlagsIsWWAN; | |
return (isReachable && isWWAN) ? YES : NO; | |
} | |
} | |
- (id)initWithHostName:(NSString*)aHostName { | |
if (self = [super init]) { | |
hostName = [aHostName retain]; | |
runLoops = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); | |
} | |
return self; | |
} | |
- (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector { | |
self.enableNotification = YES; | |
[[NSNotificationCenter defaultCenter] addObserver:notificationObserver | |
selector:notificationSelector | |
name:self.notificationName | |
object:self]; | |
} | |
- (void)removeObserver:(id)notificationObserver { | |
[[NSNotificationCenter defaultCenter] removeObserver:notificationObserver | |
name:self.notificationName | |
object:self]; | |
} | |
#pragma mark Private Method | |
- (void)updateReachabilityFlagsIfEnableNotificationIsNo { | |
@synchronized(self) { | |
if (!self.enableNotification) { | |
if (!reachabilityRef) { | |
reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [hostName UTF8String]); | |
} | |
if (!SCNetworkReachabilityGetFlags(reachabilityRef,&reachabilityFlags)) { | |
reachabilityFlags = 0; | |
} | |
} | |
} | |
} | |
- (BOOL)isScheduledOnRunLoop:(NSRunLoop *)inRunLoop { | |
@synchronized(self) { | |
CFRunLoopRef runLoop = [inRunLoop getCFRunLoop]; | |
return CFArrayContainsValue(runLoops, CFRangeMake(0, CFArrayGetCount(runLoops)), runLoop); | |
} | |
} | |
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) { | |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
Reachability *reachability = info; | |
@synchronized(reachability) { | |
reachability->reachabilityFlags = flags; | |
} | |
[[NSNotificationCenter defaultCenter] postNotificationName:[reachability notificationName] object:info]; | |
[pool release]; | |
} | |
- (void)scheduleOnRunLoop:(NSRunLoop *)inRunLoop { | |
@synchronized(self) { | |
if (hostName && inRunLoop) { | |
if (!reachabilityRef) { | |
reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [hostName UTF8String]); | |
} | |
if (reachabilityRef && ![self isScheduledOnRunLoop:inRunLoop]) { | |
CFRunLoopRef runLoop = [inRunLoop getCFRunLoop]; | |
SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL}; | |
if (SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context) && | |
SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, runLoop, kCFRunLoopDefaultMode)) { | |
CFArrayAppendValue(runLoops, runLoop); | |
} | |
} | |
} | |
} | |
} | |
- (void)unscheduleFromRunLoop:(NSRunLoop*)inRunLoop { | |
@synchronized(self) { | |
if (reachabilityRef && [self isScheduledOnRunLoop:inRunLoop]) { | |
CFRunLoopRef runLoop = [inRunLoop getCFRunLoop]; | |
if (SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, runLoop, kCFRunLoopDefaultMode)) { | |
CFIndex index = CFArrayGetFirstIndexOfValue(runLoops, CFRangeMake(0, CFArrayGetCount(runLoops)), runLoop); | |
if (index != kCFNotFound) { | |
CFArrayRemoveValueAtIndex(runLoops, index); | |
} | |
} | |
} | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment