NSOperationQueue
a waitUntilAllOperationsAreFinished
, mais je ne veux pas l'attendre de manière synchrone. Je veux simplement masquer l'indicateur de progression dans l'interface utilisateur lorsque la file d'attente se termine.
Quelle est la meilleure façon d'y parvenir?
Je ne peux pas envoyer de notifications de mes NSOperation
s, car je ne sais pas laquelle sera la dernière, et [queue operations]
peut ne pas être encore vide (ou pire - repeuplée) lorsque la notification est reçue.
Réponses:
Utilisez KVO pour observer la
operations
propriété de votre file d'attente, puis vous pouvez savoir si votre file d'attente est terminée en vérifiant[queue.operations count] == 0
.Quelque part dans le fichier dans lequel vous effectuez le KVO, déclarez un contexte pour le KVO comme celui-ci ( plus d'informations ):
Lorsque vous configurez votre file d'attente, procédez comme suit:
Ensuite, faites ceci dans votre
observeValueForKeyPath
:(Cela suppose que vous
NSOperationQueue
êtes dans une propriété nomméequeue
)À un moment donné, avant que votre objet ne se désarchive complètement (ou lorsqu'il cesse de se soucier de l'état de la file d'attente), vous devrez vous désinscrire de KVO comme ceci:
Addendum: iOS 4.0 a une
NSOperationQueue.operationCount
propriété qui, selon la documentation, est conforme au KVO. Cette réponse fonctionnera toujours dans iOS 4.0, elle est donc toujours utile pour la compatibilité ascendante.la source
operationCount
sur le mêmeNSOperationQueue
objet entraînerait potentiellement des bogues, auquel cas vous auriez besoin d'utiliser correctement l'argument de contexte. Il est peu probable que cela se produise, mais certainement possible. (Il est plus utile de préciser le problème réel que d'ajouter snark + un lien)Si vous attendez (ou souhaitez) quelque chose qui correspond à ce comportement:
Vous devez être conscient que si un certain nombre d'opérations "courtes" sont ajoutées à une file d'attente, vous pouvez voir ce comportement à la place (car les opérations sont démarrées dans le cadre de leur ajout à la file d'attente):
Dans mon projet, j'avais besoin de savoir quand la dernière opération était terminée, après qu'un grand nombre d'opérations avaient été ajoutées à une série NSOperationQueue (c'est-à-dire maxConcurrentOperationCount = 1) et seulement quand elles étaient toutes terminées.
Googling J'ai trouvé cette déclaration d'un développeur Apple en réponse à la question "est un NSoperationQueue FIFO série?" -
Dans mon cas, il est possible de savoir quand la dernière opération a été ajoutée à la file d'attente. Donc, après l'ajout de la dernière opération, j'ajoute une autre opération à la file d'attente, de priorité inférieure, qui ne fait rien d'autre que d'envoyer la notification que la file d'attente a été vidée. Compte tenu de la déclaration d'Apple, cela garantit qu'un seul avis n'est envoyé qu'une fois toutes les opérations terminées.
Si les opérations sont ajoutées d'une manière qui ne permet pas de détecter la dernière, (c'est-à-dire non déterministe), je pense que vous devez suivre les approches KVO mentionnées ci-dessus, avec une logique de garde supplémentaire ajoutée pour essayer de détecter si davantage des opérations peuvent être ajoutées.
:)
la source
Que diriez-vous d'ajouter une NSOperation qui dépend de toutes les autres pour qu'elle s'exécute en dernier?
la source
Une alternative consiste à utiliser GCD. Référez-vous à ceci comme référence.
la source
Voilà comment je fais.
Configurez la file d'attente et enregistrez-vous pour les modifications dans la propriété operations:
... et l'observateur (dans ce cas
self
) met en œuvre:Dans cet exemple, "spinner"
UIActivityIndicatorView
montre que quelque chose se passe. Évidemment, vous pouvez changer pour convenir ...la source
for
boucle semble potentiellement coûteuse (et si vous annulez toutes les opérations en même temps? Cela n'obtiendrait-il pas des performances quadratiques lorsque la file d'attente est en cours de nettoyage?)J'utilise une catégorie pour ce faire.
NSOperationQueue + Completion.h
NSOperationQueue + Completion.m
Utilisation :
Source: https://gist.github.com/artemstepanenko/7620471
la source
waitUntilFinished
devrait l'êtreYES
À partir d' iOS 13.0 , les propriétés operationCount et operation sont obsolètes. Il est tout aussi simple de suivre vous-même le nombre d'opérations dans votre file d'attente et de déclencher une notification lorsqu'elles sont toutes terminées. Cet exemple fonctionne également avec une sous-classification asynchrone d' Opération .
Vous trouverez ci-dessous une sous-classe d'opération pour des opérations asynchrones faciles
}
la source
decrementOperationCount()
méthode est-elle invoquée?Qu'en est-il de l'utilisation de KVO pour observer la
operationCount
propriété de la file d'attente? Ensuite, vous en entendrez parler lorsque la file d'attente devenait vide, et aussi lorsqu'elle cessait d'être vide. Gérer l'indicateur de progression peut être aussi simple que de faire quelque chose comme:la source
NSOperationQueue
3.1 se plaint de ne pas être conforme au KVO pour la cléoperationCount
.operationCount
propriété est présente.Ajoutez la dernière opération comme:
Alors:
la source
Avec ReactiveObjC, je trouve que cela fonctionne bien:
la source
Pour info, vous pouvez y parvenir avec GCD dispatch_group dans swift 3 . Vous pouvez être averti lorsque toutes les tâches sont terminées.
la source
Vous pouvez créer un nouveau
NSThread
, ou exécuter un sélecteur en arrière-plan et y attendre. Quand leNSOperationQueue
fin, vous pouvez envoyer une notification de votre choix.Je pense à quelque chose comme:
la source
Si vous utilisez cette opération comme classe de base, vous pouvez passer
whenEmpty {}
block à OperationQueue :la source
Sans KVO
la source
Si vous êtes ici à la recherche d'une solution avec combine - j'ai fini par écouter mon propre objet d'état.
la source