【问题标题】:Timing out a synchronous server call in a NSOperationQueue使 NSOperationQueue 中的同步服务器调用超时
【发布时间】:2014-02-06 16:15:10
【问题描述】:

我正在使用 NSOperation 队列来获取图像并将它们显示在我的 tableview 单元格上。在图像返回之前,我会显示加载叠加层,一旦操作完成,它就会提示委托,然后我删除加载叠加层。

现在,我想在 5 秒后让 fetch 操作超时并删除加载覆盖,但基于计时器的方法行不通。请提出建议。

下面是我的代码:

#import "MyImageFetchOperation.h"
#import "MyImageFetchController.h"
#import "MyHTTPRequest.h"

@interface MyImageFetchOperation ()

@property (nonatomic, strong) NSString *imageURL;
@property (nonatomic, weak) id <MyOperationCompletedDelegate> delegate;
@property (nonatomic, assign) BOOL isCompleted;
@property (nonatomic, weak) NSTimer *timeoutTimer;

@end

@implementation MyImageFetchOperation
@synthesize imageURL;
@synthesize delegate;
@synthesize isCompleted;

#define kMyImageFetchTimeout 5

#pragma mark -
#pragma mark Destruction

- (void)dealloc {
    self.delegate = nil;
}


- (id)initWithImageURL:(NSString *)iImageURL delegate:(id)iDelegate {
    if (self = [super init]) {
        self.imageURL = iImageURL;
        self.delegate = iDelegate;
    }
    return self;
}


- (void)main {
    self.isCompleted = NO;
    NSMutableURLRequest *aRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.imageURL]];
    [aRequest setTimeoutInterval:kMyImageFetchTimeout];
    [aRequest setHTTPMethod:@"GET"];

    self.timeoutTimer = [NSTimer scheduledTimerWithTimeInterval:kMyImageFetchTimeout target:self selector:@selector(requestTimedOut) userInfo:nil repeats:NO];

    [NSURLConnection sendAsynchronousRequest:aRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *iData, NSError *iConnectionError) {
        if (!self.isCompleted) {
            if (iConnectionError) {
                [[MyImageFetchController sharedRunnerImageFetchControllerMy] urlFailed:self.imageURL];
            }

            UIImage *anImage = [UIImage imageWithData:iData];

            if (anImage) {
                [MyUtilities cacheFile:anImage withName:[self.imageURL runnerMD5HashMy] toDirectory:[self.delegate cacheDirectoryForImages]];
            } else {
                [[MyImageFetchController sharedRunnerImageFetchControllerMy] urlFailed:self.imageURL];
            }

            [self.delegate operationCompletedForURL:self.imageURL];
            self.isCompleted = YES;
        }
    }];
}


- (void)requestTimedOut {
    self.isCompleted = YES;
    [self.timeoutTimer invalidate];
    self.timeoutTimer = nil;
    [[MyImageFetchController sharedRunnerImageFetchControllerMy] urlFailed:self.imageURL];
    [self.delegate operationCompletedForURL:self.imageURL];
}

@end

【问题讨论】:

  • 为什么需要计时器?您已对 URL 请求设置了超时,因此应在最迟 5 秒后调用完成处理程序,如果请求超时,则应使用 iData == nil
  • 马丁,他确实有问题。从 setTimeoutInterval 上的 NSMutableRequest.h cmets “因此,当发生负载活动的实例时(例如,从网络接收到请求的字节),请求的空闲间隔重置为 0”因此,如果他将间隔设置为5 但连接需要 4 个数据块,每个数据块需要 2 秒才能到达,连接甚至可能不会超时。

标签: ios objective-c cocoa-touch nsoperation nsoperationqueue


【解决方案1】:

你需要一个运行循环来让你的定时器工作,像这样:

- (void)main
{
    // your code
    yourTimer = ... // create your timer

    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
    [runLoop addTimer:yourTimer forMode:NSRunLoopCommonModes];
    [runLoop run];
}

哦,而且,我想最好在 main 中设置自己的自动释放池。

【讨论】:

    【解决方案2】:

    你为什么不打电话

    [self.delegate operationCompletedForURL:self.imageURL];
    

    如果在这里面?

    if (iConnectionError) {
    

    另一方面,您不应该在该块中使用 self ,您应该使用 __block 变量。

    【讨论】:

    • 好吧,无论如何都会被调用,因为这个语句不在任何 if 或 else 中。
    • 是的,你是对的。但是然后在没有计时器的情况下正确调用了代表?最好的选择是使用请求的超时时间(如您所见)而不使用计时器。
    • 是的,但是请求的超时并不能保证在该时间段内实际超时。如果服务器连接建立需要时间,但一旦建立服务器连接并且服务器响应缓慢,它就会工作,然后它遵循默认超时。
    • 检查这个:stackoverflow.com/questions/8304702/… Steven Fisher 说 NSTimer 触发它创建的线程的运行循环需要继续存在,但是您的操作线程在您发送 NSURLConnection 后立即死亡要求。尝试在主线程中启动计时器。
    猜你喜欢
    • 1970-01-01
    • 2014-07-31
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 2011-01-12
    • 1970-01-01
    相关资源
    最近更新 更多