AFNetworking/QHTTPOperation/QReachabilityOperation.m

112 lines
3.5 KiB
Mathematica
Raw Normal View History

2011-05-31 16:27:34 -05:00
#import "QReachabilityOperation.h"
@interface QReachabilityOperation ()
@property (assign, readwrite) NSUInteger flags;
static void ReachabilityCallback(
SCNetworkReachabilityRef target,
SCNetworkReachabilityFlags flags,
void * info
);
- (void)reachabilitySetFlags:(NSUInteger)newValue;
@end
@implementation QReachabilityOperation
- (id)initWithHostName:(NSString *)hostName {
assert(hostName != nil);
self = [super init];
if (self != nil) {
self->_hostName = [hostName copy];
self->_flagsTargetMask = kSCNetworkReachabilityFlagsReachable | kSCNetworkReachabilityFlagsInterventionRequired;
self->_flagsTargetValue = kSCNetworkReachabilityFlagsReachable;
}
return self;
}
- (void)dealloc {
[self->_hostName release];
assert(self->_ref == NULL);
[super dealloc];
}
@synthesize hostName = _hostName;
@synthesize flagsTargetMask = _flagsTargetMask;
@synthesize flagsTargetValue = _flagsTargetValue;
@synthesize flags = _flags;
// Called by QRunLoopOperation when the operation starts. This is our opportunity
// to install our run loop callbacks, which is exactly what we do. The only tricky
// thing is that we have to schedule the reachability ref to run in all of the
// run loop modes specified by our client.
- (void)operationDidStart {
Boolean success;
SCNetworkReachabilityContext context = { 0, self, NULL, NULL, NULL };
assert(self->_ref == NULL);
self->_ref = SCNetworkReachabilityCreateWithName(NULL, [self.hostName UTF8String]);
assert(self->_ref != NULL);
success = SCNetworkReachabilitySetCallback(self->_ref, ReachabilityCallback, &context);
assert(success);
for (NSString * mode in self.actualRunLoopModes) {
success = SCNetworkReachabilityScheduleWithRunLoop(self->_ref, CFRunLoopGetCurrent(), (CFStringRef) mode);
assert(success);
}
}
static void ReachabilityCallback(
SCNetworkReachabilityRef target,
SCNetworkReachabilityFlags flags,
void * info
)
// Called by the system when the reachability flags change. We just forward
// the flags to our Objective-C code.
{
QReachabilityOperation * obj;
obj = (QReachabilityOperation *) info;
assert([obj isKindOfClass:[QReachabilityOperation class]]);
assert(target == obj->_ref);
#pragma unused(target)
[obj reachabilitySetFlags:flags];
}
// Called when the reachability flags change. We just store the flags and then
// check to see if the flags meet our target criteria, in which case we stop the
// operation.
- (void)reachabilitySetFlags:(NSUInteger)newValue {
assert( [NSThread currentThread] == self.actualRunLoopThread );
self.flags = newValue;
if ( (self.flags & self.flagsTargetMask) == self.flagsTargetValue ) {
[self finishWithError:nil];
}
}
// Called by QRunLoopOperation when the operation finishes. We just clean up
// our reachability ref.
- (void)operationWillFinish {
Boolean success;
if (self->_ref != NULL) {
for (NSString * mode in self.actualRunLoopModes) {
success = SCNetworkReachabilityUnscheduleFromRunLoop(self->_ref, CFRunLoopGetCurrent(), (CFStringRef) mode);
assert(success);
}
success = SCNetworkReachabilitySetCallback(self->_ref, NULL, NULL);
assert(success);
CFRelease(self->_ref);
self->_ref = NULL;
}
}
@end