如何在iOS中恢复NSOperationQueue的超时操作?

时间:2016-06-27 11:33:42

标签: ios synchronization nsoperation nsoperationqueue

我已经在应用程序中成功实现了NSOperationQueue。

我有一个操作队列,可能有1000个NSOperations,如下所示。

@interface Operations : NSOperation

@end

@implementation Operations

- (void)main
{
    NSURL *url = [NSURL URLWithString:@"Your URL Here"];

    NSString *contentType = @"application/json";
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];
    NSError *err = nil;

    NSData *body = [NSJSONSerialization dataWithJSONObject:postVars options:NSJSONWritingPrettyPrinted error:&err];

    [request setHTTPBody:body];
    [request addValue:[NSString stringWithFormat:@"%lu", (unsigned long)body.length] forHTTPHeaderField: @"Content-Length"];

     [request setTimeoutInterval:60];

     NSHTTPURLResponse *response = nil;
     NSError *error = nil;

     NSData *resData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
}

@end

现在,对于该队列,我一次添加所有1000个操作。 我添加如下操作。

Operations *operation = [[Operations alloc]init];
[downloadQueue addOperation:operation];

现在时间间隔为60 [request setTimeoutInterval:60]

所以想想60秒后如果1000次操作中的300次操作完成,那么其他700次操作就会抛出请求超时错误。

那么在这种情况下我应该怎么做。

我可以恢复失败的操作吗?或者我应该再次进行操作并将其添加到队列中。

有没有比这个更好的机制?

3 个答案:

答案 0 :(得分:3)

我最初的倾向是,是的,只是为超时请求创建新操作并将其重新投入队列。它只是感觉更简单,因为您已经有了为您的请求添加这些操作的逻辑。但是:

  1. 小心不要陷入无限循环。如果其中任何一个因任何原因而无限期失败,那么你的队列将会继续发挥作用。我保留了失败次数,以便您知道在经过一些有限次的尝试后停止重试请求。

  2. 如果您知道大量数据总是会失败,请考虑以某种方式对它们进行批处理。一种选择是依赖链。例如。您可以尝试添加200个操作,一个"等待" NSOperation,下一个200,另一个"等待" NSOperation,另一个"等待" op等。使第一个等待操作依赖于前200个请求。然后使下一个200依赖于第一个等待操作,依此类推:

    • [第1批:前200个请求]
    • [等待1:等待所有批次1的操作]
    • [批次2:下一个200,每个等待等待1]
    • [等待2:等待所有批次2的操作]
    • [批次3:下一个200,每个等待等待2]
  3. 基本上就像2而不是"等待"操作,完成"完成"运。假设您有一组1000个要发送的请求:将200个放入队列,然后完成"完成" op取决于那些200.当"完成"运行(根据定义,在完成那些200之后),然后它可以从阵列中拉出下一个200并将它们扔进去(加上一个新的"完成" op)。

  4. (甚至可以考虑等待/完成操作"暂停"几秒钟让服务器喘息)

    换句话说,对于#2和#3,我说'#34;立即爆炸200,等待,然后爆炸下一个200,等待等等。" (对我来说,200是任意的,你比我更了解你的情况最佳数字)

答案 1 :(得分:2)

您可以实现NSURLConnectionDelegate方法connection:didFailWithError:来检查同步请求是否失败,以及错误是否是请求超时。然后在委托回调中重试连接。

我应该注意到Apple强烈鼓励使用NSURLSession而不是NSURLConnection,因为NSURLConnection中的许多方法现已弃用。

答案 2 :(得分:2)

第一点是 - 不要让它们全部同时运行!如果您尝试同时运行10个请求,则可以轻松地泛洪移动数据连接。因此,在其他任何事情之前,将队列的maxConcurrentOperationCount设置为类似5。

仅这一点可能会大大减少您的问题,您可能不需要做任何其他事情。

您还应该真正考虑使用NSURLSession,这样您还可以查看删除操作队列并使用HTTPMaximumConnectionsPerHost来控制同时发出的请求数。

如果你仍然失败,那么其他答案之一的“递归类型”选项之一是一个可行的解决方案。我将向操作子类添加一个尝试计数,以便于跟踪,如果失败,则检查它失败的次数,并决定是否创建操作的新副本并将其添加到队列或发出警报