【问题标题】:AFNetworking Offline QueueAFNetworking 离线队列
【发布时间】:2015-03-21 20:09:06
【问题描述】:

目前我正在使用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");
         }];
}

模式 1:

  • AirPlane 模式下的设备
  • 运行

控制台输出:

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 已激活

控制台输出续:

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

模式 2:

  • Wifi 活跃
  • 运行

控制台输出:

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 已激活

控制台输出续:

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 nothingIOS - best way to queue requests to be sent when connection is reestablished

【问题讨论】:

    标签: ios httprequest afnetworking


    【解决方案1】:

    一些观察:

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

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

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


    更多观察:

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

    2. 前面一点,如果您想要更可靠的“我可以连接到特定服务器”,您可以考虑使用managerForDomain 而不是sharedManager。只需确保对生成的 AFNetworkReachabilityManager 保持强引用,因为与单例不同,它不会对自身保持强引用。

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

      不幸的是,AFHTTPSessionManager 不是基于NSOperation。但是,如果您想享受“仅在建立连接时发送请求”功能,您可以自己将它们包装在异步NSOperation 子类中(请参阅AFNetworking 3.0 AFHTTPSessionManager using NSOperation),您可以使用后台会话(请参阅AFNetworking 2.0 and background transfers,虽然是为 AFNetworking 2.x 编写的,但概述了使用 AFHTTPSessionManager 和后台会话的要点,这仍然主要适用于版本 3)。

    【讨论】:

    • 哦,我明白了;那是我应该看到的。显然,isExecuting 值应该是线索。所以这个想法是;每当没有连接时,设备甚至都不会请求,而只是等待可达性显示 WIFI/Active。很酷!至于第 2 点,我怎么能简单地在特定操作的 failureBlock 内执行以下操作:{ [operationQueue setSuspended:YES]; [operationQueue addOperation:operation.copy]; [operationQueue setSuspended:NO]; } 这看起来不错吗?
    • 不,您不希望操作与队列的挂起状态纠缠不清。我不确定你为什么这样做。如果我们正在做一些简单的事情,我可以在失败块中想象如下内容:if ([operationQueue isSuspended]) { [operationQueue.addOperation:[operation copy]]; }。这将搞砸队列(即应该在队列顶部的东西现在在最后,所以你可能会玩弄优先级。此外,这将失去你可能拥有的任何依赖关系。我想你得玩一下这个。
    • 坦率地说,您在这里遇到了类似的竞争条件问题,但是,查看队列的 suspended 状态可能还不够好(如果您在请求中丢失连接,操作将在可达性报告问题之前可能会失败。您可能必须查看NSErrorcodedomain,确定它是否被取消,然后编写代码来处理它。
    • 谢谢,目前正在考虑是否可以以更直接的方式处理这一切。
    • 将副本添加回具有更高优先级的队列。或者重写 AFURLConnectionOperation 使重试逻辑成为核心操作的一部分。但是创建新的请求管理器只会让事情变得更糟,恕我直言。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 2014-06-04
    • 1970-01-01
    相关资源
    最近更新 更多