J'ai une méthode de calcul des données (que ce soit "maMéthode :"), et je veux déplacer l'appel vers un autre thread parce que je ne veux pas bloquer la fonctionnalité principale de mon interface utilisateur. J'ai donc commencé à faire quelques recherches sur la façon d'appeler ma méthode sur un autre thread. D'après ce que je vois, il y a actuellement beaucoup de façons différentes de le faire. En voici une liste :
a) utiliser des threads purs (disponible depuis iOS 2.0) :
[NSThread detachNewThreadSelector:@selector(myMethod:) toTarget:self withObject:_myParamsArray];
b) en utilisant un simple raccourci (disponible depuis iOS 2.0). Disponible à partir de NSObject hérité mais la méthode appartient aussi à la classe NSThread :
[self performSelectorInBackground:@selector(myMethod:) withObject:_myParamsArray];
c) en utilisant une nouvelle approche des files d'attente de Grand Central Dispatch (disponible depuis iOS 4.0) :
dispatch_async(dispatch_get_global_queue(0, 0),
^ {
[self myMethod:_myParamsArray];
});
d) d'une manière ou d'une autre, en utilisant des classes telles que NSOperation, NSBlockOperation ou NSOperationQueue, mais je ne sais pas exactement comment le faire (un exemple serait apprécié).
Actuellement, j'ai utilisé la casse "b" mais je suis curieux de connaître les avantages et les inconvénients et autres suggestions à ce sujet.
UPDATE : e) a également trouvé un autre moyen de réaliser des opérations similaires de threading - Boucles d'exécution . Voici un extrait de la documentation d'Apple :
Une boucle d'exécution est une boucle de traitement des événements que vous utilisez pour planifier le travail et coordonner la réception des événements entrants. L'objectif d'une boucle d'exécution est de garder votre thread occupé lorsqu'il y a du travail à faire et de le mettre en veille lorsqu'il n'y en a pas.
À mon avis, vous avez plus ou moins affaire à la même tâche - comment appeler votre méthode sur un thread séparé pour son opération asynchrone.
UPDATE2 : J'ai déjà eu quelques expériences avec NSInvocationOperation et NSOperationQueue et IMHO c'est assez pratique. D'après la documentation d'Apple, GCD et NSOperations sont les moyens préférés pour implémenter le multithreading. De plus, NSOperations fonctionne sur GCD à partir d'iOS 4.0. En bref, vous instanciez NSIvocationOperation (en tant qu'appel à votre méthode) puis vous instanciez NSOperationQueue et ajoutez l'invocation à la file d'attente. NSOperationQueue est assez intelligent, vous pouvez instancier plusieurs objets NSIvocationOperation (enveloppant vos appels de méthode) et les ajouter à NSOperationQueue. Le reste est assuré. NSOperationQueue détermine le nombre de threads parallèles dont il a besoin pour effectuer les appels (NSInvocationOperation) et s'en occupe pour vous. Il se peut qu'elle exécute le premier appel sur le thread A, puis le deuxième sur le thread B, le troisième sur le thread C et le quatrième sur le thread B, vous n'avez donc pas à vous en soucier. Mais si vous voulez, vous pouvez indiquer le nombre maximum de threads que NSOperationQueue peut utiliser pour exécuter les appels (par exemple 1) mais je n'en ai pas besoin. Par défaut, toutes les tâches sont effectuées sur un thread autre que le thread principal, donc les files d'opérations sont asynchrones par défaut. En outre, si vous souhaitez effectuer vos appels de méthode (chacun enveloppé dans une NSInvocationOperation distincte) dans une file d'attente stricte, vous pouvez ajouter des dépendances et ainsi NSOperationQueue préservera l'ordre des appels de méthode. Voici un exemple :
// wrap your method call into NSInvocationOperation object
NSInvocationOperation *currentOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(yourMethodCall) object:nil];
// _sharedOperationQueue is a shared NSOperationQueue
// get all executing operations from the queue and get the last operation
_lastOperation = [[_sharedOperationQueue operations] lastObject];
// check if _lastOperation is not nil
if (_lastOperation) {
// if not then add dependency, so the calls would be performed in a queue
[currentOperation addDependency:_lastOperation];
}
// say - execute my method (operation)
[_sharedOperationQueue addOperation:currentOperation];
_lastOperation = currentOperation; // mark as last operation for adding dependency to the next operation
// the queue will retain invocation operation so you will release
[currentOperation release];
..... you can create another NSInvocationOperation and add it to the queue....
En ce qui concerne les RUNLOOPs, vous y serez tout de même parfois confronté, par exemple lors du lancement/de la programmation d'une minuterie, ou lors de l'établissement de connexions NSURL. IMHO, un runloop peut être comparé à une file d'attente de tâches exécutées sur un thread. Un runloop est un pointeur vers un thread qui fonctionne comme une file d'attente : il contient des tâches qui peuvent lancer des événements et elles seront placées à la fin de la file d'attente dans ce thread. Par défaut, toutes les tâches de votre application s'exécutent dans un seul runloop - dans un seul thread. Je dis qu'il s'agit d'un pointeur car lorsque votre application génère des événements, elle doit savoir où placer cet événement (événement tactile ou autre rappel de délégué) pour qu'il soit exécuté. Bien entendu, vous devriez lire le document sur les boucles d'exécution pour obtenir des informations plus détaillées, car ce ne sont que mes réflexions.