Currently I am queueing a simple offline request using AFHTTPRequestOperationManager
and it doesn't seem to work in the desired manner:
Here is the responsible code and below are different execution patterns:
@interface ViewController ()
{
AFHTTPRequestOperationManager *manager;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
manager = [AFHTTPRequestOperationManager manager];
NSOperationQueue *operationQueue = manager.operationQueue;
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status){
NSLog(@"Reachability: %@", AFStringFromNetworkReachabilityStatus(status));
switch (status) {
case AFNetworkReachabilityStatusReachableViaWWAN:
case AFNetworkReachabilityStatusReachableViaWiFi:
NSLog(@"Operation: %@", operationQueue.operations);
[operationQueue setSuspended:NO];
NSLog(@"ONLINE");
break;
case AFNetworkReachabilityStatusNotReachable:
default:
NSLog(@"Operation: %@", operationQueue.operations);
[operationQueue setSuspended:YES];
NSLog(@"OFFLINE");
break;
}
}];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager GET:@"http://www.google.com"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id response){
NSLog(@"success");
}
failure:^(AFHTTPRequestOperation *operation, NSError *failure){
NSLog(@"failure");
}];
}
Pattern 1:
- Device on AirPlane mode
- Run
Console output:
2015-03-21 16:03:54.486 OfflineSupport[928:227748] Reachability: Not Reachable
2015-03-21 16:03:54.494 OfflineSupport[928:227748] Operation: (
"<AFHTTPRequestOperation: 0x1701d0c20, state: isExecuting, cancelled: NO request: <NSMutableURLRequest: 0x170014ab0> { URL: http://www.google.com }, response: (null)>"
)
2015-03-21 16:03:54.494 OfflineSupport[928:227748] OFFLINE
2015-03-21 16:03:54.544 OfflineSupport[928:227748] failure
- Wifi Activated
Console output contd.:
2015-03-21 16:04:05.594 OfflineSupport[928:227748] Reachability: Reachable via WiFi
2015-03-21 16:04:05.595 OfflineSupport[928:227748] Operation: (
)
2015-03-21 16:04:05.595 OfflineSupport[928:227748] ONLINE
Pattern 2:
- Wifi Active
- Run
Console output:
2015-03-21 16:05:43.818 OfflineSupport[934:228478] Reachability: Reachable via WiFi
2015-03-21 16:05:43.826 OfflineSupport[934:228478] Operation: (
"<AFHTTPRequestOperation: 0x1701dde20, state: isExecuting, cancelled: NO request: <NSMutableURLRequest: 0x17001ad10> { URL: http://www.google.com }, response: (null)>"
)
2015-03-21 16:05:43.826 OfflineSupport[934:228478] ONLINE
2015-03-21 16:05:43.960 OfflineSupport[934:228478] success
- AirPlane activated
Console output contd.:
2015-03-21 16:05:53.437 OfflineSupport[934:228478] Reachability: Not Reachable
2015-03-21 16:05:53.438 OfflineSupport[934:228478] Operation: (
)
2015-03-21 16:05:53.438 OfflineSupport[934:228478] OFFLINE
In pattern 1, the request results in the failure block as there is no access. But when the device comes online, the request is not executed again. Is there something I am missing here? Do I have to configure something on the operation queue or in the failure block?
Reference: AFNetworking 2.0 queue request when device is offline with setReachabilityStatusChangeBlock does nothing, IOS - best way to queue requests to be sent when connection is reestablished
A few observations:
In pattern 1, you have a bit of a race condition because the reachability status block runs asynchronously, so if you start reachability and immediately add operation, the status may not have been identified as being offline yet, and thus the queue may not have been suspended and thus the operation may start immediately (and fail because you're offline).
The problem is solved if you suspend the queue before starting reachability and before starting any operations. If you're actually offline, the queue will stay offline and any operations that were added will be suspended, too. But if you were really online, the reachability block will be called reasonably quickly and and the queue will be promptly be unsuspended. It eliminates this race condition.
The
suspended
state of a queue does not affect operations that have already started. In only impacts those operations that have not yet started. So, if the connection goes offline while a network operation was in progress, there is no built in mechanism to pause the operation until the connection is restored, nor restart the operation when the status changes. If you want that functionality, you'd have to implement that yourself.
A few more observations:
It's worth noting, though, that just because reachability says that connectivity is available, it doesn't guarantee that the request will succeed. You still need to gracefully handle failed requests.
To the prior point, if you want a more reliable "can I connect to a particular server", you might consider using
managerForDomain
rather thansharedManager
. Just make sure to keep a strong reference to the resultingAFNetworkReachabilityManager
, because unlike the singleton, it won't keep a strong reference to itself.The
AFHTTPRequestOperationManager
is from version 2.x, and you might consider upgrading to the latest version (so that you useAFHTTPSessionManager
, aNSURLSession
based implementation). TheNSURLConnection
used in 2.x has been deprecated.The
AFHTTPSessionManager
is, unfortunately, notNSOperation
-based. But if you want to enjoy the "send the requests only when the connection is established" functionality, you can either wrap them in asynchronousNSOperation
subclass yourself (see AFNetworking 3.0 AFHTTPSessionManager using NSOperation) you can use a background session (see AFNetworking 2.0 and background transfers, while written for AFNetworking 2.x, outlines the essentials of usingAFHTTPSessionManager
and background session which still largely applies for version 3).
来源:https://stackoverflow.com/questions/29187488/afnetworking-offline-queue