Search code examples
afnetworkingreachability

AFNetworking 2.0. How check reachability status for socket (managerForAddress:)?


I install AFNetworking 2.0 with "pod install", and use App.xcworkspace. With AFNetworking 2.0 I successfully send POST request, but with reachability I have problem. I need to monitor when socket is opened and closed, my code not work, what I forgot?

// Check server socket available
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_len = sizeof(serverAddr);
serverAddr.sin_port = htons(80);
serverAddr.sin_addr.s_addr = inet_addr("192.168.1.108");

AFNetworkReachabilityManager *reachability = [AFNetworkReachabilityManager managerForAddress:&serverAddr];
[reachability setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
    switch (status) {
        case AFNetworkReachabilityStatusNotReachable:
            NSLog(@"No Internet Connection");
            break;
        case AFNetworkReachabilityStatusReachableViaWiFi:
            NSLog(@"WIFI");
            break;
        case AFNetworkReachabilityStatusReachableViaWWAN:
            NSLog(@"3G");
            break;
        default:
            NSLog(@"Unknown network status");
            break;
    }
}];
[reachability startMonitoring];

Solution

  • I think I figured out the issue. Looks like AFNetworking's callback mechanism doesn't work as it should - check out AFNetworkReachabilityManager's startMonitoring method: there's an:

            if (strongSelf.networkReachabilityStatusBlock) {...
    

    which seems to fail no matter if you've set up a callback or not.

    To fix this, I've added the following method to AFNetworkReachabilityManager:

    - (void)startMonitoringWithStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block
    {
        [self stopMonitoring];
    
        if (!self.networkReachability) {
            return;
        }
    
        __weak __typeof(self)weakSelf = self;
        AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
            __strong __typeof(weakSelf)strongSelf = weakSelf;
    
            strongSelf.networkReachabilityStatus = status;
            if (block) {
                block(status);
            }
        };
    
        SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
        SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
    
        SCNetworkReachabilityFlags flags;
        SCNetworkReachabilityGetFlags(self.networkReachability, &flags);
        dispatch_async(dispatch_get_main_queue(), ^{
            AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
            callback(status);
        });
    
        SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
    }
    

    This basically does the same thing but references the block from the method parameter rather than from the reachability manager's property.