Bouton prioritaire
tablier
Membre
Dans Repertoire, J'ai une méthode récursive qui analyse une hiérarchie de dossier-fichier. Classique!
Suite au conseil de Lugdanum, j'ai fait un certain nombre de modifications dont l'ajout d'un bouton "Stop" qui devrait être prioritaire.
Ce que je prévoyais: un clic sur le bouton Stop met un Flag à YES et la méthode récursive tient compte du flag pour ressortir immédiatement.
Mais, quoi que je fasse, le bouton stop n'est pas vu pendant que cette méthode est exécutée!
Je crois comprendre que la méthode qui se rappelle elle-même ne laisse pas de temps libre pour l'interface utilisateur.
En cherchant à droite et à gauche, il me semble que l'on résout cela en utilisant NSThread.
Est-ce que je continue sur cette voie ou dois-je regarder ailleurs?
Suite au conseil de Lugdanum, j'ai fait un certain nombre de modifications dont l'ajout d'un bouton "Stop" qui devrait être prioritaire.
Ce que je prévoyais: un clic sur le bouton Stop met un Flag à YES et la méthode récursive tient compte du flag pour ressortir immédiatement.
Mais, quoi que je fasse, le bouton stop n'est pas vu pendant que cette méthode est exécutée!
Je crois comprendre que la méthode qui se rappelle elle-même ne laisse pas de temps libre pour l'interface utilisateur.
En cherchant à droite et à gauche, il me semble que l'on résout cela en utilisant NSThread.
Est-ce que je continue sur cette voie ou dois-je regarder ailleurs?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Il y a plein de possibilités de faire du code concurrentiel (qui s'exécute en parallèle). utiliser les threads directement en est une, mais plutôt bas niveau (tu auras beaucoup de choses à gérer toi-même pour faire du thread-safety, gérer la synchro des ressources, éviter les deadlocks, et anticiper les cas un peu tricky genre race-conditions...), et cela apporte des problématiques en général vite complexes.
Il y a plein de solutions alternatives plutôt que d'utiliser NSThread directement qui sont encore plus haut niveau ou plus adaptées et t'évitent de te prendre le chou avec divers détails.
- Par exemple manipuler NSRunLoop pour déclencher une itération de ta reccursivité à chaque itération de RunLoop, laissant la RunLoop continuer de faire, en plus de ton itération de parcours, les vérifications d'interaction utilisateur.
- Ou utiliser NSOperationQueue, et empiler tes opérations (à chaque dossier rencontré, tu crées une nouvelle NSOperation dédiée qui va scanner ce dossier, et tu "empiles" cette NSOperation dans ta NSOperationQueue dédiée pour qu'elle s'exécute quand elle aura du temps dispo)
- Ou utiliser GCD et dispatch_async pour envoyer des blocs de code s'exécuter de façon asynchrone (donc non bloquante pour l'interface) sur des "Queue" GCD.
Toutes ces solutions dans leur ensemble te poseront moins de problèmes que NSThread. Celle utilisant NSOperationQueue étant peut-être la plus simple à comprendre (concept d'empiler des opérations) tout en ayant une API Cocoa.
Tu crées une sous-classe ScanOperation de NSOperation spécialisée dans ton opération de scan d'un dossier donné en paramètre, et qui boucle sur son contenu, exécute une action donnée pour les fichiers (action que tu peux même envisager passer en paramètre via un block, tiens, tant qu'on y est), et crées d'autres objets ScanOperation quand il rencontre un sous-dossier. Tu vas empiler tes ScanOperations sur une NSOperationQueue et elle s'exécuteront en parallèle (bien plus puissant même qu'un algo reccursif car cela fait les scans des dossiers également en parallèle et pas en séquentiel) et pendant que la NSOperationQueue va les exécuter en arrière-plan (gérant elle-même toutes les subtilités des threads ou queue qu'elle pourra créer pour faire ça sur un thread autre que le main thread) ton main thread et ta main RunLoop pourront toujours intercepter les actions utilisateurs.
Je t'invite fortement à lire le Concurrency Programming Guide qui explique pourquoi il faut mieux éviter NSThread, et quelles sont les différentes autres techniques avec leurs avantages et inconvénients, etc.
J'ai une question subsidiaire. Dans l'exemple NSOperationSample j'ai trouvé: quelle est la porté de LoadImageDidFinish? Globale tant que l'objet LoadOperation existe?
Ce qui me parait curieux: cette variable déclarée dans l'implementation de LoadOperation est déclarée extern dans le LoadOperation.h. Je ne comprends pas vraiment cela.
Et puis surtout il n'y a pas de raison de permettre de changer la valeur vers laquelle pointe LoadImageDidFinish, donc c'est bien plus logique d'en faire une constante.
Autant les variables globales c'est le mal, autant les constantes sont souvent déclarées dans l'espace global, pour être accessibles de partout (mais en lecture uniquement donc il n'y a pas les soucis qu'on peut avoir avec les variables globales). Seule truc du coup quand tu déclares une constante dans l'espace global, c'est de lui donner un nom assez différenciant pour être à la fois explicite et éviter que le nom rentre en conflit avec une autre constante.
Je ne sais pas pourquoi dans l'exemple que tu cites ils n'ont pas déclaré ça en "const" comme pour toutes les notifications qu'on trouve dans Cocoa... ceci dit les exemples d'Apple sont connus pour être juste là "pour comprendre le principe de base de fonctionnement" donc allant au plus simple pour ne pas t'embrouiller avec des détails, et pas pour être "des modèles de conception et d'archi et de bons usages".
Pour déclarer une NSString constante dans les règles de l'art :
Voilà j'espère que ça t'aidera à y voir plus clair.
En général donc les notifications dans Cocoa sont déclarées avec "extern" dans le .h, et leur valeur est définie dans le .m (que tu ne vois pas puisqu'il est compilé dans le framework Cocoa)
Eventuellement ça a + de sens uniquement conceptuellement / pour la lecture du code de les mettre à l'intérieur du @implementation si elles sont "liées" à ta classe, c'est plus clair à la lecture, mais au niveau de la compilation si je ne m'abuse ça change rien.
Comme dit dans la doc, c'est quelque chose à prévoir à l'origine!