AFNetworking 离线队列
Posted
技术标签:
【中文标题】AFNetworking 离线队列【英文标题】:AFNetworking Offline Queue 【发布时间】: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 nothing,ios - best way to queue requests to be sent when connection is reestablished
【问题讨论】:
【参考方案1】:一些观察:
在模式 1 中,由于可达性状态块是异步运行的,因此您有一点竞争条件,因此如果您启动可达性并立即添加操作,则状态可能尚未被识别为离线,因此队列可能尚未暂停,因此操作可能会立即开始(并且由于您处于离线状态而失败)。
如果在开始可达性之前和开始任何操作之前暂停队列,问题就解决了。如果您实际上处于脱机状态,则队列将保持脱机状态,并且添加的任何操作也将暂停。但是如果你真的在线,可达性块将被相当快地调用,并且队列将被立即解除暂停。它消除了这种竞争条件。
队列的suspended
状态不会影响已经开始的操作。仅影响那些尚未开始的操作。因此,如果在网络操作正在进行时连接脱机,则没有内置机制可以暂停操作直到连接恢复,也没有在状态更改时重新启动操作。如果您需要该功能,则必须自己实现。
更多观察:
值得注意的是,仅仅因为可达性表明连接可用,它并不能保证请求会成功。你仍然需要优雅地处理失败的请求。
前面一点,如果您想要更可靠的“我可以连接到特定服务器”,您可以考虑使用managerForDomain
而不是sharedManager
。只需确保对生成的 AFNetworkReachabilityManager
保持强引用,因为与单例不同,它不会对自身保持强引用。
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
状态可能还不够好(如果您在请求中丢失连接,操作将在可达性报告问题之前可能会失败。您可能必须查看NSError
的code
和domain
,确定它是否被取消,然后编写代码来处理它。
谢谢,目前正在考虑是否可以以更直接的方式处理这一切。
将副本添加回具有更高优先级的队列。或者重写 AFURLConnectionOperation 使重试逻辑成为核心操作的一部分。但是创建新的请求管理器只会让事情变得更糟,恕我直言。以上是关于AFNetworking 离线队列的主要内容,如果未能解决你的问题,请参考以下文章
AFNetworking:如何知道响应是不是使用缓存? 304 或 200