filteredArrayUsingPredicate: sur le main thread avec réception du resultat
Flo
Membre
Bonjour à tous,
quelqu'un aurait-il une solution élégante pour résoudre ce problème :
de mon côté je vois plusieurs solutions qui ne me plaisent pas vraiment :
- une catégorie sur NSArray, du genre filteredArrayUsingPredicate: (NSPredicate *)predicate results: (NSArray **)results
- exécuter le filtrage dans une méthode plus générale lancée sur le main thread
merci d'avance pour votre (précieuse) aide
quelqu'un aurait-il une solution élégante pour résoudre ce problème :
<br />result = [_tradeSites performSelectorOnMainThread: @selector(filteredArrayUsingPredicate:) withObject: predicate waitUntilDone: YES];<br />
de mon côté je vois plusieurs solutions qui ne me plaisent pas vraiment :
- une catégorie sur NSArray, du genre filteredArrayUsingPredicate: (NSPredicate *)predicate results: (NSArray **)results
- exécuter le filtrage dans une méthode plus générale lancée sur le main thread
merci d'avance pour votre (précieuse) aide
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
A l'origine la recherche est lancée par un thread concurrent.
Le tableau à filtrer contient des objets qui peuvent être modifiés par le main thread. J'ai pensé que comme mon NSPredicate interrogeait ces objets, il était nécessaire de lancer la recherche également sur le main thread pour éviter les accès concurrents... me trompe-je ?
Mais je me pose deux petites questions :
Pas d'idées ??
Alors :
1) performSelectorOnMainThread n'exécute pas directement la méthode. Il empile l'appel de la méthode dans une pile de la RunLoop dédiée à ça, qui empile donc les appels en attente. Ensuite, quand la RunLoop boucle, au début de chaque cycle, elle dépile ces appels mis en attente et les exécute.
C'est exactement comme les NSTimers, qui sont "schedulés" sur la RunLoop donc mis dans une pile, et à chaque boucle de la RunLoop le système vérifie tous les timers "schedulés" et regarde s'il y en a à déclencher (si leur date a expiré). Bah là c'est pareil.
Alors que @synchronized (ou l'utilisation des @property atomic) placent un mutex, donc bloquent le thread appelant si le mutex est déjà pris, mais au moins ensuite ne chamboulent pas l'ordre d'exécution des méthodes.
Autrement dit si tu as un truc asynchrone à faire, genre "bon quand t'auras le temps, enfin quand le thread principal aura la main et fera un tour de runloop, exécute ce selector sur le thread principal), ce qui est typiquement le cas pour une mise à jour de l'interface, alors utilise performSelectorOnMainThread.
Si tu veux faire des accès concurrents ordonnancés (entre autres s'ils sont synchrones et que tu attends une réponse de leur part, mais pas que), utilise @synchronized. Ce sont deux usages bien distincts dans leur buts et motivations en tout cas.
Mais normalement si tu mets bien tes @synchronized sur uniquement la ressource (variable, ...) à protéger contre les accès concurrentiels, et pas sur un super gros bloc (genre si tu as une boucle for qui dans chaque itération accède à une variable, mettre le @synchronize à l'intérieur de la boucle "for" et non à l'exétieur permet aux autres threads d'accéder à cette variable entre les cycles de la boucle "for" au lieu de bloquer son accès pendant toute la boucle), pour ce genre de cas où tu ne fais pas des accès massifs avec des calculs intensifs, ça va pas bloquer bien longtemps, voire ça va pas bloquer du tout sauf dans de rares cas où les accès sont concurrentiels mais du coup ça va éviter les crash.
Pour la question 2, oui il y a des risques de conflits même avec uniquement de la lecture. C'est moins trivial et visible à voir, après tout c'est pas comme le risque qu'on écrive une variable pendant qu'on est aussi en train de la lire, mais bon, c'est jamais trop prudent de tout façon même si ce n'est que de la lecture, je conseillerai quand même de mettre des @synchronized.
De toute façon ne t'inquiètes pas, si t'as pas un algo de folie avec des mutex dans tous les sens risquant des deadlocks, et si tu fais les choses propres, les @synchronized ne vont pas ralentir ton code. Enfin si, bien sûr, loe positionnement des mutex va prendre quelques microsecondes, et si tu as un accès concurrent ça va être bloquant quelques millisecondes (mais ça va éviter que ça crash), à la limite... mais bon, c'est pas ça qui devrait faire laguer ton appli je veux dire. Tant que c'est pas du calcul intensif où la moindre microseconde gagnée est importante, te prend pas la tête et privilégie la protection de tes ressources par mutex ou @synchronized à l'optimisation des temps d'accès au risque de crasher si accès concurrents, quoi.
Héhé, je savais bien que tu ne m'avais pas abandonné !
Merci pour cette réponse constructive et pertinente ! C'est exactement ce que je voulais savoir !