如何从同步转换为异步NSURLConnection

时间:2015-03-12 19:49:38

标签: objective-c asynchronous nsurl synchronous

我试图更新我在ASOC中编写的旧Mac OS程序(主要是Applescript,但有一些ObjC对象用于Web服务访问)。我使用了同步连接:

NSData *resultsData = [NSURLConnection sendSynchronousRequest: req returningResponse: &response error: &err];

服务器凭据已嵌入URL中。这对我来说很好,因为在获取数据时程序确实无法继续执行任何操作。但是,对服务器身份验证方法的更改迫使需要更改此应用程序。我已尝试使用NSURLCredential的所有常用解决方法,但仍无法使用此服务。

所以看起来我需要更改为异步调用:

[[NSURLConnection alloc] initWithRequest:request
                                delegate:self 
                        startImmediately:YES];

我使用适当的委托方法,最重要的是:

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

虽然我喜欢使用某种形式的延迟循环来检查数据何时完成加载(基本上再次使其同步),但我还没有找到一种方法来实现这一点,但实际上并没有阻止连接。

我可以在继续之前使用NSTimer等待数据:

set theJobListTimer to current application's NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(0.05, me, "jobListTimerFired:", "", true)

    on jobListTimerFired_(theTimer)
      (jobListData as list) & count of jobListData
    if count of jobListData ≠ 0  then
        log "jobListTimerFired_ done"
        tell theTimer to invalidate()
        setUpJobList(jobListData)
    end if
end jobListTimerFired_

但这是笨拙的,而且我在模态对话框中不起作用:

    set buttonReturned to current application's NSApp's runModalForWindow_(collectionWindow)

(我在对话框中有一个下拉列表,需要使用Web服务调用的结果进行更新)。现在,委托方法被阻止,直到模态被解除。

使用异步方法是否没有简单的方法来模拟同步调用?

尝试使用信号量,我将代码更改为:

- (void) startConnection:(int)reqType :(NSMutableURLRequest *)request {

requestType = [NSNumber numberWithInt:reqType];

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    // This could be any block that is run asynchronously
    void (^myBlock)(void) = ^(void) {

        self.connection = [[NSURLConnection alloc] initWithRequest:request
                                                          delegate:self 
                                                  startImmediately:YES];

    myBlock();

if (self.connection) {
        // create an object to hold the received data
        self.receivedData = [NSMutableData data];
        NSLog(@"connection started %@", requestType);
    }

   dispatch_time_t timeOut = dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC);
    dispatch_semaphore_wait(semaphore, timeOut);
    dispatch_release(semaphore);
    semaphore = NULL;
}

然后在连接处理程序中:

- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"connectionDidFinishLoading %@", requestType);

NSString *returnData = [[NSString alloc] initWithData:receivedData
                                             encoding:NSUTF8StringEncoding] ;
//      NSLog(@"connectionDidFinishLoading %@", returnData);

[self handleData:requestType :returnData];

[self terminate];

if(semaphore) {
    dispatch_semaphore_signal(semaphore);
}
}

但是,在10秒调度超时之后才会调用connectionDidFinishLoading处理程序(以及didReceiveResponse和didReceiveData处理程序)。我在这里缺少什么?

2 个答案:

答案 0 :(得分:2)

您可以使用dispatch_semaphore_wait将任何异步API再次转换为同步API。

以下是一个例子:

__block BOOL accessGranted = NO;

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

// This could be any block that is run asynchronously
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
    accessGranted = granted;
    if(semaphore) {
        dispatch_semaphore_signal(semaphore);
    }
});

// This will block until the semaphore has been signaled
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_release(semaphore);
semaphore = NULL;

return accessGranted;

答案 1 :(得分:0)

在这里找到答案:

iOS, NSURLConnection: Delegate Callbacks on Different Thread?

我知道连接正在另一个线程上运行,并尝试了其他各种循环来等待它完成。但这真的是神奇的界限:

    while(!self->finished]){
    //This line below is the magic!
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}