AFNetworking checking Availability
Asked Answered
B

3

19

I've implemented AFNetworking without subclassing AFHTTPClient, in part using the following code in my DownloadQueueManager:

-(void)downloadPodcastAt:(NSString *)url toPath:(NSString *)path
{
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]
                                             cachePolicy:NSURLRequestReturnCacheDataElseLoad
                                         timeoutInterval:60.0];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

    operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
    {
        [self saveQueuedItemInformation];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error)
    {
        // Other stuff
    }];

    [operation start];
}

My question is manifold. I've googled til' my fingers went numb, and have yet to find a decent code sample that simply and easily checks for Reachability status using AFNetworking. (Oddly, there is plenty of discussion about importing SystemConfiguration.framework, which seems like a no-brainer). So if my user wants to minimize their data usage, and only download using wifi, how do I check for wifi, and only download if wifi is available?

Second, it seems like AFNetworking wants to be a user-friendly front-end. But I could actually use a front-end to this front-end, because there's a LOT of stuff in there that one has to weed through to get to the stuff one needs. I just need to access a url, download an xml file (based on reachability), and do stuff with it. Am I missing something that makes this a simple task ?

When I make sense of this, I'm totally building a front-end or five to simplify implementation (assuming I'm not just an idiot). Thanks in advance for any responses.

Burchfield answered 23/2, 2013 at 14:33 Comment(2)
Reachability isn't part of AFNetworking, you'll have to rely either on it's notification or do a status-check manually. It makes sense as you might want to check connectivity before the user is even able to try loading something, and networking operations could use cache or return an error.Beaudoin
But AFNetworking uses Availability, and implements something very similar to what Reachability implements in order to check for connection status. My question was primarily how to access those enumerated variables most efficiently.Burchfield
N
45

Actually contrary to what A-Live said Reachability IS a part of AFNetworking. It's implemented in AFHTTPClient.h here. You need the correct imports in your .pch file as discussed here in order to use it.

To use it you'll probably want to have a subclass of AFHTTPClient so you can use setReachabilityStatusChangeBlock defined here. Here's a simple example without using a subclass.

AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:@"http://google.com"]];
[client setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
    if (status == AFNetworkReachabilityStatusNotReachable) {
        // Not reachable
    } else {
        // Reachable
    }

    if (status == AFNetworkReachabilityStatusReachableViaWiFi) {
        // On wifi
    }
}];

If you don't like how this reachability setup works then I would recommend Tony Million's fork of Apple's Reachability. Simple example:

Reachability *reach = [Reachability reachabilityWithHostname:@"google.com"];
if ([reach isReachable]) {
    // Reachable
    if ([reach isReachableViaWiFi]) {
        // On WiFi
    }
} else {
    // Isn't reachable

    [reach setReachableBlock:^(Reachability *reachblock)
    {
        // Now reachable
    }];

    [reach setUnreachableBlock:^(Reachability*reach)
    {
        // Now unreachable
    }];
}
Nassir answered 23/2, 2013 at 17:4 Comment(9)
Will this continue to monitor reachability status, or is it a one-time thing?Burchfield
The blocks continue to monitor. If you wanted to stop them you could set the blocks to nil (or the equivalent)Nassir
I use afnetworking reachablity block, but it never fires and [httpClient networkReachabilityStatus] always return -1, any advice how to get it work?Foetation
@Foetation assuming you don't have compiler warnings about missing frameworks (fix here) then my first guess is if you're using it on iOS it may not work in the simulator, you may have to be on an actual device.Nassir
@KeithSmiley check this for my code and info. Frameworks are included, no warning in xcode. Using iPhone 4, iOS 6.1. #15453385Foetation
Note the wrong '=' on reach setUnreachableBlock = ^(Reachability*reach). It must be ':'. Anyway the answer is correct.Deleterious
I think AFHTTPClient *client is depreciated in the newest versionPoleyn
@KeithSmiley - This block would also notify failure if Google.com was down. That would not mean that internet is unavailable. Is there no way to differentiate between the 2 scenarios? I mean to say how to find out if internet connectivity is available on device, regardless of my web server being reachable or not.Old
As stated above this code is now obsolete. While I think it's safe to rely on the reachability of google.com that was intended to be a placeholder for the web service URL you're actually trying to access.Nassir
I
20

With AFNetworking 2.0 and above, one can check for availability like this,

    [[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
    switch (status) {
        case AFNetworkReachabilityStatusUnknown:
        case AFNetworkReachabilityStatusReachableViaWWAN:
        case AFNetworkReachabilityStatusReachableViaWiFi:
            //available
            break;
        case AFNetworkReachabilityStatusNotReachable:
            //not available
            break;
        default:
            break;
    }

    NSLog(@"Reachability: %@", AFStringFromNetworkReachabilityStatus(status));

}];

//start monitoring
[[AFNetworkReachabilityManager sharedManager] startMonitoring];

To get current status

[AFNetworkReachabilityManager sharedManager].reachable
Irresistible answered 29/9, 2014 at 13:0 Comment(1)
This is the correct answer for AFNetworking 2.0, although Im finding that the block isn't called reliablyGymnasiarch
P
8

Just an update, the newer version of AFNetworking has deprecated AFHTTPClient.

You can use AFHTTPRequestOperationManager.h instead

Something small taken from the github page itself:

AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url]; //url can be google.com or something you want to reach

NSOperationQueue *operationQueue = manager.operationQueue;
[manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status)

{
    switch (status)
    {
        case AFNetworkReachabilityStatusReachableViaWWAN:
        case AFNetworkReachabilityStatusReachableViaWiFi:
        {
            NSLog(@"SO REACHABLE");
            [operationQueue setSuspended:NO]; // or do whatever you want
            break;
        }

        case AFNetworkReachabilityStatusNotReachable:
        default:
        {
            NSLog(@"SO UNREACHABLE");
            [operationQueue setSuspended:YES]; 
            //not reachable,inform user perhaps
            break;
        }
    }
}];
[manager.reachabilityManager startMonitoring];
Poleyn answered 4/6, 2014 at 20:2 Comment(2)
However this will not give current status if reachability would not change. To check for the current status, [AFNetworkReachabilityManager sharedManager].reachable one should do like this.Irresistible
Using [manager.reachabilityManager isReachable] to check the current status works for me.Confab

© 2022 - 2024 — McMap. All rights reserved.