NSOperationQueue
tem waitUntilAllOperationsAreFinished
, mas não quero esperar sincronizadamente por isso. Eu só quero ocultar o indicador de progresso na interface do usuário quando a fila terminar.
Qual é a melhor maneira de fazer isso?
Não posso enviar notificações do meu NSOperation
s, porque não sei qual vai ser a última, e [queue operations]
posso não estar vazio ainda (ou pior - preenchido novamente) quando a notificação for recebida.
Respostas:
Use KVO para observar a
operations
propriedade de sua fila, então você pode saber se sua fila foi concluída verificando[queue.operations count] == 0
.Em algum lugar do arquivo em que você está fazendo o KVO, declare um contexto para o KVO como este ( mais informações ):
Ao configurar sua fila, faça o seguinte:
Então faça isso no seu
observeValueForKeyPath
:(Isso pressupõe que você
NSOperationQueue
está em uma propriedade chamadaqueue
)Em algum ponto antes de seu objeto ser totalmente desalocado (ou quando ele parar de se preocupar com o estado da fila), você precisará cancelar o registro do KVO desta forma:
Adendo: iOS 4.0 possui uma
NSOperationQueue.operationCount
propriedade que, de acordo com os documentos, é compatível com KVO. Essa resposta ainda funcionará no iOS 4.0, portanto, ainda é útil para compatibilidade com versões anteriores.fonte
operationCount
no mesmoNSOperationQueue
objeto poderia levar a bugs, caso em que você precisaria usar o argumento de contexto corretamente. É improvável que ocorra, mas definitivamente possível. (Soletrar o problema real é mais útil do que adicionar snark + um link)Se você está esperando (ou deseja) algo que corresponda a este comportamento:
Você deve estar ciente de que, se várias operações "curtas" estiverem sendo adicionadas a uma fila, você poderá ver este comportamento (porque as operações são iniciadas como parte da adição à fila):
Em meu projeto, eu precisava saber quando a última operação foi concluída, depois que um grande número de operações foi adicionado a um NSOperationQueue serial (ou seja, maxConcurrentOperationCount = 1) e somente quando todas foram concluídas.
Pesquisando no Google, encontrei esta declaração de um desenvolvedor da Apple em resposta à pergunta "is a serial NSoperationQueue FIFO?" -
No meu caso é possível saber quando a última operação foi adicionada à fila. Então, depois que a última operação é adicionada, eu adiciono outra operação à fila, de menor prioridade, que não faz nada além de enviar a notificação de que a fila foi esvaziada. De acordo com a declaração da Apple, isso garante que apenas um único aviso seja enviado somente após a conclusão de todas as operações.
Se as operações estão sendo adicionadas de uma maneira que não permite detectar a última (ou seja, não determinística), então eu acho que você deve ir com as abordagens KVO mencionadas acima, com lógica de guarda adicional adicionada para tentar detectar se mais operações podem ser adicionadas.
:)
fonte
Que tal adicionar uma operação NSO que é dependente de todas as outras para que seja executada por último?
fonte
Uma alternativa é usar o GCD. Consulte isso como referência.
fonte
É assim que eu faço.
Configure a fila e registre-se para alterações na propriedade de operações:
... e o observador (neste caso
self
) implementa:Neste exemplo, "spinner"
UIActivityIndicatorView
mostra que algo está acontecendo. Obviamente, você pode mudar para se adequar ...fonte
for
loop parece potencialmente caro (e se você cancelar todas as operações de uma vez? Isso não teria um desempenho quadrático quando a fila estivesse sendo limpa?)Estou usando uma categoria para fazer isso.
NSOperationQueue + Completion.h
NSOperationQueue + Completion.m
Uso :
Fonte: https://gist.github.com/artemstepanenko/7620471
fonte
waitUntilFinished
deveria serYES
Como de iOS 13,0 , o operationCount e operação propriedades estão obsoletos. É muito simples controlar o número de operações em sua fila e disparar uma Notificação quando todas elas forem concluídas. Este exemplo também funciona com uma subclasse assíncrona de Operation .
Abaixo está uma subclasse de Operação para operações assíncronas fáceis
}
fonte
decrementOperationCount()
método é invocado?Que tal usar KVO para observar a
operationCount
propriedade da fila? Então, você ouviria quando a fila esvaziasse e também quando ela parasse de esvaziar. Lidar com o indicador de progresso pode ser tão simples quanto fazer algo como:fonte
NSOperationQueue
from 3.1 reclama que não é compatível com KVO para a chaveoperationCount
.operationCount
propriedade está presente.Adicione a última operação como:
Assim:
fonte
Com ReactiveObjC acho que isso funciona muito bem:
fonte
Para sua informação, você pode conseguir isso com GCD dispatch_group no swift 3 . Você pode ser notificado quando todas as tarefas forem concluídas.
fonte
Você pode criar um novo
NSThread
ou executar um seletor em segundo plano e aguardar lá. QuandoNSOperationQueue
terminar, você mesmo pode enviar uma notificação.Estou pensando em algo como:
fonte
Se você usar esta Operação como sua classe base, poderá passar o
whenEmpty {}
bloco para OperationQueue :fonte
Sem KVO
fonte
Se você chegou aqui procurando uma solução com combine - acabei ouvindo apenas meu próprio objeto de estado.
fonte