我试图更新我在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处理程序)。我在这里缺少什么?
答案 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]];
}