4

Мне нужно рассчитать дорогостоящее значение. После вычисления этого значения я хотел бы запустить блок обработки завершений:Objective-C wait для асинхронных операций и обработчиков завершения очереди.

-(void) performCostlyCalculationWithCompletionHandler:(void (^)(void)complete 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     id result = [self costlyCalculation]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      complete(result); 
     }); 
    }); 
} 

Довольно стандартный.

Теперь, я хотел бы иметь возможность называть эту функцию повторно, без повторного enqueueing costlyCalculation. Если costlyCalculation уже работает, я хотел бы просто сохранить блокировки завершения и назвать их всех одним и тем же result после завершения costlyCalculation.

Есть ли простой способ сделать это с помощью GCD или NSOperationQueue? Или я должен просто хранить блоки завершения в NSArray и называть их сам? Если я это сделаю, какую синхронизацию мне нужно установить вокруг этого массива?

UPDATE

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

dispatch_group_t group = dispatch_group_create(); 

dispatch_queue_t queue = dispatch_get_global_queue(0, 0); 
dispatch_group_async(group, queue, ^(){ 
    // Do something that takes a while 
    id result = [self costlyCalculation]; 
    dispatch_group_async(group, dispatch_get_main_queue(), ^(){ 
     self.result = result; 
    }); 
}); 

dispatch_group_notify(group, dispatch_get_main_queue(), ^(){ 
    complete(result); 
}); 

Этой работы, но как я могу сказать, если costlyCalcuation уже работает и не епдиеяя работу, если я не нужно?

+0

Не могли бы вы сохранить результат как ivar, а затем проверить существование «результата» перед выполнением «costlyCalculation» или просто пометить начало и конец функции с помощью BOOL, а затем, если функция запущена, добавьте блок к массиву, как указано в вашем q, и вызвать все блоки в очереди после завершения вычисления. Я уже делал обе эти вещи, если вам нужен какой-то код. –

+0

Не хотите проверять «результат» заранее, потому что несколько запросов будут выполняться быстро, пока он работает в первый раз, что приведет к дублированию вызовов «costlyCalculation». Возможно, обозначение начала и конца BOOLs - правильный путь. Спасибо за предложение. – bcattle

+0

Конечно, я использую 'AVAssetImageGenerator' для создания эскизов из актива. Затем миниатюры вставляются в несколько «CALayers» в разных местах на экране. Видимые слои могут появляться и исчезать при запуске 'AVAssetImageGenerator'. – bcattle

ответ

1

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

// somewhere, create operation queue 
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init]; 

-(void)tryCalculation:(CompletionBlockType)completionBlock 
{ 
    if(opQueue.operationCount > 0) 
    { 
     NSOperation *op = [[NSOperation alloc] init]; 
     op.completionBlock = completionBlock; 
     // you can control how to synchronize completion blocks by changing dependency object. In this example, all operation will be triggered at once when costly calculation finishes 
     [op addDependency:[opQueue.operations firstObject]]; 
     [opQueue addOperation:op]; 
    } 
    else 
    { 
     NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(costlyCalculation) object:nil]; 
     op.completionBlock = completionBlock; 
     [opQueue addOperation:op]; 
    } 
} 

Тем не менее, может возникнуть тонкая проблема с синхронизацией. Возможно, мы могли бы использовать дополнительный флаг в функции costCalculation.

+0

Спасибо за код. Какой вопрос времени вы представляете? – bcattle

+0

@ bcattle Теоретически, costcoCalculation может завершиться при создании объекта NSOperation в первом блоке. Вы создали новую операцию, в которой есть операция, от которой зависит, но после ее создания она исчезла. Я не уверен, что произойдет в таком случае :) – Wonjae

+0

Этот код предполагает, что выполняемая задача сама по себе является синхронной. Если это асинхронно, вы должны обернуть его [асинхронным подклассом NSOperation] (https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationObjects/OperationObjects.html#//apple_ref/ doc/uid/TP40008091-CH101-SW8) или, что еще хуже, заставить его вести себя синхронно с помощью семафоров или тому подобного. – Rob

Смежные вопросы