AFNetworking 离线队列

AFNetworking Offline Queue

目前我正在使用 AFHTTPRequestOperationManager 对一个简单的离线请求进行排队,但它似乎没有以预期的方式工作:

这是负责的代码,下面是不同的执行模式:

@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");
         }];
}

模式一:

控制台输出:

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

控制台输出续:

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

模式二:

控制台输出:

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

控制台输出续:

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

在模式 1 中,请求导致失败块,因为没有访问权限。但是当设备上线时,请求不会再次执行。我在这里缺少什么吗?我必须在操作队列或失败块中配置一些东西吗?

参考: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

几点观察:

  1. 在模式 1 中,您有一点竞争条件,因为可达性状态块异步运行,因此如果您启动可达性并立即添加操作,状态可能不会被识别为离线但是,因此队列可能尚未挂起,因此操作可能会立即开始(并且由于您处于离线状态而失败)。

    如果在开始可达性和开始任何操作之前挂起队列,问题就解决了。如果您实际上处于离线状态,队列将保持离线状态,并且添加的任何操作也将被暂停。但是如果你真的在线,reachability block 会被相当快地调用并且队列会被立即取消挂起。它消除了这种竞争条件。

  2. 队列的suspended状态不影响已经开始的操作。仅影响那些尚未开始的操作。因此,如果在进行网络操作时连接脱机,则没有内置机制来暂停操作直到连接恢复,也没有在状态更改时重新启动操作。如果您想要该功能,则必须自己实现。


更多观察:

  1. 但值得注意的是,仅仅因为可达性表示连接可用,并不能保证请求一定会成功。您仍然需要优雅地处理失败的请求。

  2. 对于前面的一点,如果你想要更可靠的"can I connect to a particular server",你可以考虑使用managerForDomain而不是sharedManager。只需确保对结果 AFNetworkReachabilityManager 保持强引用,因为与单例不同,它不会保持对自身的强引用。

  3. AFHTTPRequestOperationManager来自版本2.x,您可以考虑升级到最新版本(以便您使用AFHTTPSessionManagerNSURLSession 基于实现)。 2.x 中使用的 NSURLConnection 已被弃用。

    不幸的是,AFHTTPSessionManager 不是基于 NSOperation 的。但是如果你想享受 "send the requests only when the connection is established" 功能,你可以自己将它们包装在异步 NSOperation 子类中(参见 ) you can use a background session (see AFNetworking 2.0 and background transfers,虽然为 AFNetworking 2.x 编写,概述了使用 AFHTTPSessionManager 和仍然主要适用于版本 3 的后台会话)。