NSOperationQueue 和 ASIHTTPRequest

Posted

技术标签:

【中文标题】NSOperationQueue 和 ASIHTTPRequest【英文标题】:NSOperationQueue and ASIHTTPRequest 【发布时间】:2010-07-24 21:56:44 【问题描述】:

我正在为围绕ASIHTTPRequest 编写的包装类编写测试用例。由于我无法确定的原因,我的测试用例在 ASIHTTPRequest 完成之前完成并失败。

这是程序流程的工作原理。

    从我的测试用例开始。 初始化我的 http 引擎对象,指示它创建一个新列表 创建新的 ASIHTTPRequest 对象并进行设置。 将请求添加到操作队列。 等到该队列为空 检查是否调用了我的委托方法,如果没有调用,则测试失败。

现在,大多数情况下一切正常并且测试通过,但有时它会失败,因为在操作队列将控制权返回给我的等待方法之后调用了我的委托方法。

测试用例

// Set my flags to 'NO'
- (void)setUp 
    requestDidFinish = NO;
    requestDidFail = NO;


- (void)testCreateList 
    NSString *testList = @"\"title\": \"This is a list\"";

    JKEngine *engine = [[JKEngine alloc] initWithDelegate:self];
    NSString *requestIdentifier = [engine createList:jsonString];

    [self waitUntilEngineDone:engine];
    NSString *responseString = responseString_;
    [engine release];

    GHAssertNotNil(requestIdentifier, nil);
    GHAssertTrue(requestDidFinish, nil);
    GHAssertTrue([responseString hasPrefix:@"\"CreateOrEditListResult\""], nil);



// Puts the test into a holding pattern until the http request is done
- (void)waitUntilEngineDone:(JKEngine *)engine 
    [engine waitUntilFinishedRunning]; 


// The delegate method called on successful completion
- (void)requestFinished:(NSString *)requestIdentifier withResponse:(NSString *)response 
    NSLog(@"request did finish");
    requestDidFinish = YES;
    responseIdentifier_ = [requestIdentifier retain];
    responseString_ = [response retain];

引擎代码

- (NSString *)createList:(NSString *)list 
    ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:url]];
    [request addRequestHeader:@"Content-Type" value:kContentType];
    [request setRequestMethod:kPOST];
    request.delegate = self;

    [request appendPostData:[list dataUsingEncoding:NSUTF8StringEncoding]];

    NSString *requestIdentifier = [NSString stringWithNewUUID];

    [operationQueue_ addOperation:request];
    [operationDictionary_ setObject:request forKey:requestIdentifier];

    return requestIdentifier;


// This is the ASIHTTPRequest delegate method that's called on success
//   but it sometimes isn't called until AFTER the operationQueue finishes running
- (void)requestFinished:(ASIHTTPRequest *)request 
    DLog([request responseString]);

    BOOL canNotifiyDelegate = [self.delegate respondsToSelector:@selector(requestFinished:withResponse:)];
    if (canNotifiyDelegate) 
        NSArray *keyArray = [operationDictionary_ allKeysForObject:request];
        NSString *requestIdentifier = [keyArray objectAtIndex:0];
        [operationDictionary_ removeObjectForKey:requestIdentifier];

        if ([keyArray count] != 1) 
            ALog(@"It looks like a request was added to the operation dictionary multiple times. There's a bug somewhere.", nil);
        

        [self.delegate requestFinished:requestIdentifier withResponse:[request responseString]];
    


- (void)waitUntilFinishedRunning 
    [operationQueue_ waitUntilAllOperationsAreFinished];

【问题讨论】:

【参考方案1】:

这就是 ASIHTTPRequest 的工作方式。委托方法在主线程上调用,并且对委托的调用不会阻塞请求线程,因此很有可能在队列结束后调用您的委托。

【讨论】:

实际上,这就是我期望它工作的方式。让我陷入循环的是,有时在队列完成后调用委托方法。如果有帮助,所有测试都在主线程上运行。 对不起,我说反了,你描述的就是正在发生的事情。您知道测试请求是否完成的可靠方法吗?听起来唯一的方法是轮询我当前的对象并确定是否已调用 requestFinished 或 requestFailed。【参考方案2】:

ASIHTTPRequest 在主线程上调用委托方法,默认情况下GH-Unit 在后台线程上运行其测试。我对到底发生了什么还有些模糊,但强制我的网络测试在主线程上运行解决了这个问题。

我在我的网络测试类中实现了以下方法。

- (BOOL)shouldRunOnMainThread  
    return YES;

【讨论】:

以上是关于NSOperationQueue 和 ASIHTTPRequest的主要内容,如果未能解决你的问题,请参考以下文章

多线程编程NSOperationQueue

NSOperationQueue 和并发操作

gcd和NSOperationQueue区别

NSOperationQueue 和 ASIHTTPRequest

iOS 使用 NSOperationQueue 和 AFNetworking 实现多下载功能

使用 NSOperationQueue 在单独的线程上创建自动释放的对象