Travailler avec la classe NSOperationQueue

Le multitâche empêche les applications de geler. Dans la plupart des langages de programmation, réaliser ceci est un peu délicat, mais la classe NSOperationQueue dans iOS facilite la tâche.!

Ce tutoriel montrera comment utiliser le NSOperationQueue classe. Un objet NSOperationQueue est une file d’attente qui gère les objets du NSOperation type de classe. Un objet NSOperation, simplement exprimé, représente une tâche unique, comprenant à la fois les données et le code associé à la tâche. NSOperationQueue gère et gère l'exécution de tous les objets NSOperation (les tâches) qui lui ont été ajoutés. L'exécution a lieu avec le thread principal de l'application. Lorsqu'un objet NSOperation est ajouté à la file d'attente, il est exécuté immédiatement et il ne quitte pas la file d'attente avant la fin. Une tâche peut être annulée, mais elle n'est pas retirée de la file d'attente avant la fin. La classe NSOperation est abstraite et ne peut donc pas être utilisée directement dans le programme. Au lieu de cela, il existe deux sous-classes fournies, la NSInvocationOperation la classe et la NSBlockOperation classe. Je vais utiliser le premier dans ce tutoriel.


Le projet exemple

Voici l'objectif de ce didacticiel: pour chaque thread supplémentaire, nous voulons que notre application crée un objet NSInvocationOperation (NSOperation). Nous allons ajouter chaque objet dans NSOperationQueue, puis nous aurons terminé. La file d'attente se charge de tout et l'application fonctionne sans gel. Pour démontrer clairement l'utilisation des classes que j'ai mentionnées ci-dessus, nous allons créer un exemple de projet (simple) dans lequel, outre le fil principal de l'application, nous aurons deux autres threads qui le suivront. Sur le premier thread, une boucle sera exécutée de 1 à 10 000 000 et une étiquette sera mise à jour toutes les 100 étapes avec la valeur du compteur de la boucle. Sur le deuxième fil, l'arrière-plan d'une étiquette se remplira d'une couleur personnalisée. Ce processus se déroulera dans une boucle et sera exécuté plusieurs fois. Nous aurons donc quelque chose comme un rotateur de couleur. En même temps, les valeurs RVB de la couleur d'arrière-plan personnalisée ainsi que la valeur du compteur de boucles seront affichées à côté de l'étiquette. Enfin, nous allons utiliser trois boutons pour changer la couleur d’arrière-plan de la vue sur le fil principal. Ces tâches ne pourraient pas être exécutées simultanément sans tâches multiples. Voici un aperçu du résultat final:


Étape 1: Créer le projet

Commençons par créer le projet. Ouvrez le Xcode et créez un nouveau Application à vue unique.

Cliquez sur Suivant et donnez un nom au projet. Je l'ai nommé ThreadingTestApp. Vous pouvez utiliser le même nom ou tout autre nom que vous aimez.

Suivant. terminer la création du projet.


Étape 2: configuration de l'interface

Clique sur le ViewController.xib fichier pour révéler le constructeur d'interface. Ajoutez les contrôles suivants pour créer une interface similaire à l'image suivante:

  1. Barre de navigation
    • Cadre (x, y, W, H): 0, 0, 320, 44
    • Teinte: couleur noire
    • Titre: "Démo Simple Multi-Threading"
  2. UILabel
    • Cadre (x, y, W, H): 20, 59, 280, 21
    • Texte: "Counter at Thread # 1"
  3. UILabel
    • Cadre (x, y, W, H): 20, 88, 280, 50
    • Couleur de fond: Couleur gris clair
    • Couleur du texte: Couleur gris foncé
    • Texte: -
  4. UILabel
    • Cadre (x, y, W, H): 20, 154, 280, 21
    • Texte: "Rotateur de couleur aléatoire au filetage 2"
  5. UILabel
    • Cadre (x, y, W, H): 20, 183, 100, 80
    • Couleur de fond: Couleur gris clair
    • Texte: -
  6. UILabel
    • Cadre (x, y, W, H): 128, 183, 150, 80
    • Texte: -
  7. UILabel
    • Cadre (x, y, W, H): 20, 374, 280, 21
    • Texte: "Couleur de fond du fil principal"
  8. UIButton
    • Cadre (x, y, W, H): 20, 403, 73, 37
    • Titre: "Couleur # 1"
  9. UIButton
    • Cadre (x, y, W, H): 124, 403, 73, 37
    • Titre: "Couleur # 2"
  10. UIButton
    • Cadre (x, y, W, H): 228, 403, 73, 37
    • Titre: "Couleur # 3"

Pour le dernier UILabel et les trois boutons UIB, définissez le paramètre Autosizing valeur à En bas à gauche pour rendre l'interface agréable sur l'iPhone 4 / 4S et l'iPhone 5, exactement comme l'image suivante:


Étape 3: Propriétés IBOutlet et méthodes IBAction

Dans cette prochaine étape, nous allons créer les propriétés IBOutlet et les méthodes IBAction nécessaires au bon fonctionnement de notre exemple d'application. Pour créer de nouvelles propriétés et méthodes et les connecter à vos contrôles en tant qu'Interface Builder, cliquez sur le bouton du milieu du bouton Editeur dans la barre d'outils Xcode pour afficher le Assistant rédacteur:

Tous les contrôles n'ont pas besoin d'une propriété de sortie. Nous n'en ajouterons qu'un pour les UILabels 3, 5 et 6 (selon l'ordre dans lequel ils ont été énumérés à l'étape 2), nommé label1, label2 et label3.

Pour insérer une nouvelle propriété de sortie, Ctrl + clic (clic droit) sur une étiquette> cliquez sur la nouvelle prise de référencement> glisser-déposer dans l'assistant d'édition. Ensuite, spécifiez un nom pour la nouvelle propriété, comme dans les images suivantes:

Insertion d'une nouvelle propriété IBOutlet


Définition du nom de la propriété IBOutlet

Répétez la procédure ci-dessus trois fois pour connecter les trois UILabels aux propriétés. À l'intérieur de votre ViewController.h fichier vous avez ces propriétés déclarées:

 @property (hold, nonatomic) IBOutlet UILabel * label1; @property (hold, nonatomic) IBOutlet UILabel * label2; @property (hold, nonatomic) IBOutlet UILabel * label3;

Ajoutez maintenant les méthodes IBAction pour les trois boutons UIB. Chaque bouton changera la couleur de fond de la vue. Pour insérer une nouvelle méthode IBAction, Ctrl + Clic (clic droit) sur un UIButton> Cliquez sur Retouche à l'intérieur> Glisser-déposer dans l'éditeur adjoint.. Après cela, spécifiez un nom pour la nouvelle méthode. Examinez les images suivantes et l'extrait suivant pour les noms de méthodes:


Insertion d'une nouvelle méthode IBAction
Définition du nom de la méthode IBAction

Encore une fois, répétez le processus ci-dessus trois fois pour connecter chaque UIButton à une méthode d'action. le ViewController.h Le fichier doit maintenant contenir:

 - (IBAction) applyBackgroundColor1; - (IBAction) applyBackgroundColor2; - (IBAction) applyBackgroundColor3;

Les propriétés IBOutlet et les méthodes IBAction sont maintenant prêtes. Nous pouvons maintenant commencer à coder.


Étape 4: L'objet NSOperationQueue et les déclarations de méthode liées à la tâche nécessaires

L’une des tâches les plus importantes à faire est de déclarer un NSOperationQueue object (notre file d’opérations), qui sera utilisé pour exécuter nos tâches dans les threads secondaires. Ouvrez le ViewController.h déposer et ajouter le contenu suivant juste après la @interface entête (n'oubliez pas les accolades):

 @interface ViewController: UIViewController NSOperationQueue * operationQueue; 

En outre, chaque tâche doit avoir au moins une méthode contenant le code qui s'exécutera simultanément avec le thread principal. Selon la description introductive, la première tâche de la méthode sera nommée contre-tâche et le second sera nommé colorRotatorTask:

 -(vide) counterTask; - (void) colorRotatorTask;

C'est tout ce dont nous avons besoin. Notre ViewController.h Le fichier devrait ressembler à ceci:

 @interface ViewController: UIViewController NSOperationQueue * operationQueue;  @property (retenue, non atomique) IBOutlet UILabel * label1; @property (hold, nonatomic) IBOutlet UILabel * label2; @property (hold, nonatomic) IBOutlet UILabel * label3; - (IBAction) applyBackgroundColor1; - (IBAction) applyBackgroundColor2; - (IBAction) applyBackgroundColor3; - (vide) counterTask; - (void) colorRotatorTask; @fin

Passons à la mise en œuvre.


Étape 5: mise en œuvre

Nous avons presque fini. Nous avons configuré notre interface, établi toutes les connexions nécessaires, déclaré toutes les méthodes IBAction et autres nécessaires et établi notre base. Maintenant il est temps de construire sur eux.

Ouvrez le ViewController.m déposer et aller au viewDidLoad méthode. La partie la plus importante de ce tutoriel va se dérouler ici. Nous allons créer un nouveau NSOperationQueue exemple et deux NSOperation (NSInvocationOperation) objets. Ces objets encapsuleront le code des deux méthodes que nous avons précédemment déclarées, puis ils seront exécutés seuls par la méthode. NSOperationQueue. Voici le code:

 - (void) viewDidLoad [super viewDidLoad]; // Créer une nouvelle instance NSOperationQueue. operationQueue = [NSOperationQueue new]; // Créer un nouvel objet NSOperation à l'aide de la sous-classe NSInvocationOperation. // Dites-lui d'exécuter la méthode counterTask. NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget: auto-sélecteur: @selector (counterTask) object: nil]; // Ajoute l'opération à la file d'attente et la laisse être exécutée. [operationQueue addOperation: operation]; [libération de l'opération]; // Même histoire que ci-dessus, il suffit de dire ici pour exécuter la méthode colorRotatorTask. operation = [[NSInvocationOperation alloc] initWithTarget: auto-sélecteur: @selector (colorRotatorTask) object: nil]; [operationQueue addOperation: operation]; [libération de l'opération]; 

Tout ce processus est vraiment simple. Après avoir créé le NSOperationQueue Par exemple, nous créons un objet NSInvocationOperation (opération). Nous définissons sa méthode de sélection (le code que nous voulons exécuter sur un thread séparé), puis nous l'ajoutons à la file d'attente. Une fois entré dans la file d'attente, il commence immédiatement à courir. Après cela, l'objet opération peut être libéré, car la file d'attente est désormais responsable de son traitement. Dans ce cas, nous créons un autre objet et nous l'utilisons de la même manière pour la deuxième tâche (colorRotatorTask)..

Notre tâche suivante consiste à implémenter les deux méthodes de sélecteur. Commençons par écrire le contre-tâche méthode. Il contiendra un pour boucle qui fonctionnera pour un grand nombre d'itérations et toutes les 100 étapes du label1Le texte de sera mis à jour avec la valeur du compteur de l'itération actuelle (je). Le code est simple, alors voici tout:

 -(void) counterTask // Créez une boucle BIG et laissez-la mettre à jour le label1 UILabel avec la valeur du compteur. pour (int i = 0; i<10000000; i++)  if (i % 100 == 0)  // Notice that we use the performSelectorOnMainThread method here instead of setting the label's value directly. // We do that to let the main thread to take care of showing the text on the label // and to avoid display problems due to the loop speed. [label1 performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:@"%d", i] waitUntilDone:YES];   // When the loop gets finished then just display a message. [label1 performSelectorOnMainThread:@selector(setText:) withObject:@"Thread #1 has finished." waitUntilDone:NO]; 

Veuillez noter qu'il est recommandé (même par Apple) de réaliser des mises à jour visuelles sur l'interface à l'aide du fil principal et non directement à partir d'un fil secondaire. Par conséquent, l'utilisation de performSelectorOnMainThread méthode est nécessaire dans des cas tels que celui-ci.

Maintenant, implémentons le colorRotatorTask méthode:

 -(void) colorRotatorTask // Nous avons besoin d'une couleur personnalisée pour fonctionner. UIColor * customColor; // Exécuter une boucle avec 500 itérations. pour (int i = 0; i<500; i++)  // Create three float random numbers with values from 0.0 to 1.0. float redColorValue = (arc4random() % 100) * 1.0 / 100; float greenColorValue = (arc4random() % 100) * 1.0 / 100; float blueColorValue = (arc4random() % 100) * 1.0 / 100; // Create our custom color. Keep the alpha value to 1.0. customColor = [UIColor colorWithRed:redColorValue green:greenColorValue blue:blueColorValue alpha:1.0]; // Change the label2 UILabel's background color. [label2 performSelectorOnMainThread:@selector(setBackgroundColor:) withObject:customColor waitUntilDone:YES]; // Set the r, g, b and iteration number values on label3. [label3 performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:@"Red: %.2f\nGreen: %.2f\nBlue: %.2f\Iteration #: %d", redColorValue, greenColorValue, blueColorValue, i] waitUntilDone:YES]; // Put the thread to sleep for a while to let us see the color rotation easily. [NSThread sleepForTimeInterval:0.4];  // Show a message when the loop is over. [label3 performSelectorOnMainThread:@selector(setText:) withObject:@"Thread #2 has finished." waitUntilDone:NO]; 

Vous pouvez voir que nous avons utilisé le performSelectorOnMainThread méthode ici aussi. La prochaine étape est la [NSThread sleepForTimeInterval: 0.4]; Cette commande est utilisée pour provoquer un bref délai (0,4 seconde) dans chaque exécution de boucle. Même s'il n'est pas nécessaire d'utiliser cette méthode, il est préférable de l'utiliser ici pour ralentir la vitesse de changement de couleur de l'arrière-plan. label2 UILabel (notre rotateur de couleur). De plus, dans chaque boucle, nous créons des valeurs aléatoires pour le rouge, le vert et le bleu. Nous définissons ensuite ces valeurs pour produire une couleur personnalisée et la définir comme couleur de fond dans label2 UILabel.

À ce stade, les deux tâches qui vont être exécutées simultanément avec le thread principal sont prêtes. Implémentons les trois méthodes (très simples) d'IBAction et nous sommes prêts à commencer. Comme je l'ai déjà mentionné, les trois boutons UIB vont modifier la couleur d'arrière-plan de la vue, le but ultime étant de montrer comment le fil principal peut être exécuté parallèlement aux deux autres tâches. Les voici:

 - (IBAction) applyBackgroundColor1 [self.view setBackgroundColor: [UIColor colorWithRed: 255.0 / 255.0 vert: 204.0 / 255.0 bleu: 102.0 / 255.0 alpha: 1.0]];  - (IBAction) applyBackgroundColor2 [self.view setBackgroundColor: [UIColor colorWithRed: 204.0 / 255.0 vert: 255.0 / 255.0 bleu: 102.0 / 255.0 alpha: 1.0]];  - (IBAction) applyBackgroundColor3 [self.view setBackgroundColor: [UIColor whiteColor]]; 

C'est tout! Vous pouvez maintenant exécuter l'application et voir comment trois tâches différentes peuvent être exécutées simultanément. N'oubliez pas que lorsque l'exécution des objets NSOperation est terminée, il quitte automatiquement la file d'attente..


Conclusion

Beaucoup d'entre vous ont peut-être déjà découvert que le code nécessaire à l'exécution d'une application multitâche ne nécessite que quelques lignes de code. Il semble que la plus grande charge de travail consiste à mettre en œuvre les méthodes requises qui fonctionnent avec chaque tâche. Néanmoins, cette méthode est un moyen simple de développer des applications multi-threading sous iOS..