Как ждать окончания асинхронного метода? - PullRequest
1 голос
/ 13 июня 2011

У меня есть инструментарий, с которым мне нужно работать (для взаимодействия с удаленным сервисом).Этот инструментарий запрашивает удаленную службу и запрашивает результаты.Это делается асинхронно, что в большинстве случаев хорошо , но не для создания кратких методов.Я хочу создать методы, подобные следующим:

-(NSArray *)getAllAccounts {
    NSString *query = @"SELECT name FROM Account";
    //Sets "result" to the query response if no errors.
    //queryResult:error:context: is called when the data is received
    [myToolkit query:query target:self selector:@selector(queryResult:error:context:) context:nil];

    //Wait?

    return result.records;
}

Проблема в том, что внутри инструментария методы вызывают друг друга с использованием @selector, а не прямых вызовов, поэтому получение возвращаемых значений затруднено.Кроме того, фактический запрос использует:

NSURLConnection *connection = [[[NSURLConnection alloc] initWithRequest:aRequest delegate:self] autorelease];

Что является асинхронным.К тому времени, когда данные были получены от службы, мой метод давно вернулся ... без информации.Поэтому мой вопрос заключается в следующем: есть ли способ приостановить выполнение, пока данные не будут возвращены?Могу ли я выполнить это, используя второй поток для получения данных, пока основной поток отдыхает (или используя 3 потока, чтобы основной поток не отдыхал?)

Я не хочу редактировать инструментарий, чтобы изменить ихметод (или добавить новый), чтобы быть синхронным, так есть ли способ сделать метод, как я хочу?

Ответы [ 2 ]

5 голосов
/ 13 июня 2011

Возможно, вы захотите НЕ делать все синхронно, особенно если пример кода в вашем посте запущен в основной ветке приложения.Если вы сделаете это, основной поток заблокирует пользовательский интерфейс, и приложение перестанет отвечать, пока удаленная транзакция не будет завершена.

Поэтому, если вы действительно настаиваете на синхронном подходе, то вам определенно следует сделать это вфоновый поток, чтобы пользовательский интерфейс не переставал отвечать на запросы, что может привести к тому, что ваше приложение будет убито операционной системой на iphone.

Для работы в фоновом потоке я настоятельно рекомендую использовать Grand CentralОтправка материала, а именно NSBlockOperation.Это избавит вас от необходимости фактически создавать потоки и управлять ими и сделает ваш код довольно аккуратным.

Чтобы сделать это синхронно, взгляните на документацию по классу NSCondition.Вы можете сделать что-то вроде следующего:

NSCondition* condition = ...;
bool finished = NO;

-(NSArray *)getAllAccounts {
    [condition lock];
    NSString *query = @"SELECT name FROM Account";
    //Sets "result" to the query response if no errors.
    //queryResult:error:context: is called when the data is received
    [myToolkit query:query target:self selector:@selector(queryResult:error:context:) context:nil];

    while (!finished)
        [condition wait]; 

    [condition unlock];
    return result.records;
}

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

- (void) queryResult:error:context: {
    //  Deal with results
    [condition lock]
    finished = YES;
    [condition signal];
    [condition unlock];
}

Возможно, вы захотите инкапсулироватьпеременные «condition» и «done» в объявлении класса.

Надеюсь, это поможет.

ОБНОВЛЕНИЕ: Вот некоторый код для разгрузки работы в фоновый поток:

NSOperationQueue* queue = [NSOperationQueue new];
[queue addOperationWithBlock:^{
    //  Invoke getAllAccounts method
}];

Конечно, вы можете сохранить очередь для дальнейшего использования и переместить фактическую очередь работы в вызов вашего метода, чтобы сделать вещи более аккуратными.

3 голосов
/ 13 июня 2011

Способ ожидания - вернуться из текущего кода. Завершите выполнение того, что вы хотите сделать после ожидания, в указанном вами методе асинхронного обратного вызова. Что в этом такого сложного?

Любое синхронное ожидание в основном потоке пользовательского интерфейса блокирует пользовательский интерфейс и заставляет пользователя думать, что ваше приложение заблокировано, что, вероятно, намного хуже, чем вы думаете, что код не является достаточно кратким.

...