NSOperationQueue具有同步NSURLConnection

时间:2013-11-26 19:05:56

标签: ios objective-c nsurlconnection nsoperationqueue

基于earlier问题构建: 我的NSOperationQueue看起来像这样:

NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
        [someObject someSelector];
    }];

NSBlockOperation *block2= [NSBlockOperation blockOperationWithBlock:^{
    [someObject anotherSelector];
}];

[block2 addDependency:block1];
[queue addOperation:block1];
[queue addOperation:block2];

现在,在someSelector里面我有:

returnData = [requesterObj getDataWithURL:(NSString*)url];

其中getDataWithURL包含以下内容:

NSURL *requestUrl = [NSURL URLWithString:strUrl];

NSMutableURLRequest *request = [NSMutableURLRequest requestUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:timeout];
NSError *requestError;
NSURLResponse *urlResponse = nil;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];

现在,当我添加断点时,似乎在第一个块的NSURLConnection完成之前调用了第二个块。大概是因为对getDataWithURL的调用本身是异步的。在该请求返回之前,确保第一个块未完成的最佳方法是什么。我应该尝试使用NSInvocation将数据放入returnData吗?

4 个答案:

答案 0 :(得分:1)

NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
    [someObject someSelector];
}];

这会创建一个“标准”块操作。即使从用户的角度来看异步网络操作没有完成,在执行块之后,此操作也被视为已完成([block1 isFinished]为真)。

由于您不希望这样,因此您需要通过覆盖NSOperation来明确来明确 通过覆盖其start来告诉它:

- (void)completeOperation {

    self.finished = YES;
    self.executing = NO;
}

- (void)start {

    if ([self isCancelled]) {
        [self completeOperation];
        return;
    }

    self.executing = YES;
    [self main];
    // this is where operation is set to finished in NSOperation 
}

- (void)main { 
    [someObject someSelectorWithCompletionBlock: ^() { 
        [self completeOperation]; 
        // retain cycle may exist unless completion block is destroyed afterwards
    }];
}

答案 1 :(得分:1)

我个人更喜欢grand central dispatch,因为它使代码非常明显。此代码将按顺序调用两个选择器(来自另一个线程),然后在主线程上调用doneSelector

dispatch_async(dispatch_get_global_queue(0,0), ^{
    // These will be called in sequence on a background thread
    [someObject someSelector];
    [someObject anotherSelector]

    dispatch_async(dispatch_get_main_queue(), ^{
        // These will be called on the main thread after the above are done
        [someObject doneSelector];
        NSLog(@"Finished operation");
    });
});

答案 2 :(得分:0)

如果它适用于您的情况,我会让事情更简单并执行以下操作。

NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
    [someObject someSelector];
    [someObject anotherSelector];
}];
[queue addOperation:block1];

答案 3 :(得分:0)

当您第一次发布your other question时,我猜测您可能一直在处理异步网络请求,如果您希望使用异步网络请求进行操作,通常会解决在子类{{1}中包含此类网络请求的问题。 } as I discussed in the answer to your other question(以及ilya随后也在这里描述)。

此处的问题表明您正在致电NSOperation。如果这就是您所做的一切,那么就不需要sendSynchronousRequest子类化模式,并且您应该能够毫无意外地使用NSOperation。但是,看起来您发现addDependency本身就是将getDataWithURL提交给自己的操作队列,从而有效地使其异步。您正确地确定了如果从sendSynchronousRequest中删除了冗余操作队列逻辑,那么您的问题就解决了,并且不需要getDataWithURL子类化。

但是,我不会过于迅速地忽略这个子类NSOperation模式,因为NSOperation有一些限制你可能会妨碍自己。即,这些请求无法取消。同样,您无法在这些请求正在进行时获得进展,也无法处理任何高级功能,如质询 - 响应身份验证等。您可能不需要任何这些功能,但由于这些限制,我们中的许多人通常都会回避sendSynchronousRequest(以及sendSynchronousRequest)。

从长远来看,您可能会发现自己被基于NSURLConnectionDataDelegate的网络呼叫所吸引,这些呼叫解决了这些限制。在这种情况下,此sendAsynchronousRequest子类模式可能再次变得有用。或者,更好的是,考虑使用像AFNetworking这样的框架来提供基于NSOperation的网络解决方案,但是为您做了很多这样的工作。