Сделайте так, чтобы блоки iOS выполнялись синхронно - PullRequest
19 голосов
/ 07 июля 2011

Как сделать так, чтобы блок выполнялся синхронно, или чтобы функция ожидала обработчик до оператора return, чтобы данные могли быть переданы обратно из блока?

-(id)performRequest:(id)args
{
__block NSData *data = nil;   

    [xyzclass requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
        data = [NSData dataWithData:responseData];
    }];

    return data;
}

Ответы [ 6 ]

26 голосов
/ 17 января 2014

В этом случае вы можете использовать семафоры.

-(id)performRequest:(id)args
{
    __block NSData *data = nil;   
     dispatch_semaphore_t sem = dispatch_semaphore_create(0);
     [xyzclass requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
       data = [NSData dataWithData:responseData];
       dispatch_semaphore_signal(sem);
     }];
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    return data;
}

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

4 голосов
/ 17 декабря 2013

асинхронность почти всегда лучше. но если вы хотите синхронно:

-(id)performRequest:(id)args
{
__block NSData *data = nil;   

    [xyzclass requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
        data = [NSData dataWithData:responseData];
    }];

    while(!data) {
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
    }
    return data;
}

Отказ от ответственности: CocoaCouchDeveloper говорит, что, конечно, это будет работать только в том случае, если блок завершения и цикл запуска находятся в одном потоке. Я предположил, что, поскольку многие (большинство) обработчики COMPLETION, которые я знаю, работают именно так, но в принципе это справедливо.

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

2 голосов
/ 24 июля 2012

Вы можете просто добавить метод, который обрабатывает возвращенные данные, и вызвать его в своем блоке:

-(void)performRequest:(id)args{
    __block NSData *data = nil;   

    [xyzclass requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
        data = [NSData dataWithData:responseData];
        [self processData:data]; //method does something with the data 
    }];
}
0 голосов
/ 07 июля 2011

Вы могли бы сделать так.

-(id)performRequest:(id)args
{
__block NSData *data = nil;   

 [xyzclass performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse          *urlResponse, NSError *error) {

     dispatch_sync( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{

     data = [NSData dataWithData:responseData];

     });

 }];

return data;
}
0 голосов
/ 07 июля 2011

Вы уверены, что хотите сделать это синхронно? если да, вы можете вызвать (или поместить) функцию-обработчик в свой блок или использовать совет Jignesh (и использовать «executeSelectorInMainThread», когда ваш обработчик закончен и вы хотите вернуть значения.

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

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

0 голосов
/ 07 июля 2011

Вы можете сделать синхронный запрос в другом потоке, как показано ниже: код

-(void)performRequest:(id)args
{

 NSURLResponse *response = nil;
 NSError *error = nil;
 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
 data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
}

Из основного потока вы можете вызвать этот

[self performSelectorInBackground:@selector(performRequest:) withObject:args];

, или же вы можете сделать асинхронный запрос, используя следующий метод

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

и реализовать методы делегата для NSURLConnection

...