2015-03-12 4 views
2

Я пытаюсь обновить старую программу Mac OS, которую я написал в ASOC (в основном Applescript, но некоторые объекты ObjC для таких вещей, как доступ к веб-сервису). Я использовал синхронное соединение:Как преобразовать из синхронного в асинхронный NSURLConnection

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) 

(У меня есть диалоги, которые нужно обновить с результатами вызова веб-службы). Прямо сейчас методы делегата блокируются до тех пор, пока модаль не будет уволен.

Нет ли простого способа эмулировать синхронный вызов с использованием методов async?

Попытка использовать семафор, я изменил код:

- (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); 
} 
} 

Однако обработчик connectionDidFinishLoading (и на то пошло didReceiveResponse и didReceiveData обработчики) не вызывается до истечения 10-секундного тайм-аута отправки. Что мне здесь не хватает?

ответ

2

Вы можете использовать dispatch_semaphore_wait, чтобы снова добавить асинхронный 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; 
+0

Так что, кажется, есть та же самая проблема - в «dispatch_semaphore_wait», кажется, блокировать NSURLConnection. Вот что я имею: –

0

Найдено ответ здесь:

iOS, NSURLConnection: Delegate Callbacks on Different Thread?

Я знал, что связь работала на другом потоке и попытался различные другие в то время как петли, чтобы ждать его, чтобы Конец.Но это была действительно волшебная линия:

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