Vous voici donc arrivés au premier TP !
TP signifie « Travaux Pratiques ». En clair, vous allez pratiquer ce que nous venons de voir. Régulièrement, je vous ferai travailler grâce à ce genre d'exercices et vous allez vite voir que, mine de rien, vous en savez des choses.
Évidemment, je ne vous demanderai jamais rien que vous ne soyez capables de faire. Enfin pas vraiment… Il se peut que cela arrive, mais dans ce cas je vous donnerai la marche à suivre pour parvenir à la fin du TP.
Bon, vous êtes prêts ? Alors allons-y !
Instructions pour réaliser le TP
Dans ce premier programme, votre device va choisir un nombre de quatre chiffres au hasard. Vous devrez le trouver en un minimum d'essais en proposant des nombres de quatre chiffres. Pour chaque proposition, le nombre de chiffres bien placés sera indiqué. Le résultat attendu se trouve à la figure suivante.

Pour parvenir à ce résultat, vous devrez :
définir une application basée sur le modèle
Single View Application
;créer l'interface de l'application dans Interface Builder ;
relier les éléments de l'interface au code Objective-C ;
tirer au hasard un nombre de quatre chiffres ;
afficher le clavier lorsque le joueur clique dans la zone de saisie et l'effacer lorsqu'il valide sa saisie en appuyant sur
Retour
;écrire les instructions nécessaires pour comparer les nombres proposés par le joueur et le nombre à découvrir et afficher un message en conséquence.
Normalement, seule l'étape 4 devrait vous poser un problème. Les autres ont déjà été vues ; si vous avez le moindre problème avec, n'hésitez pas à lire les chapitres précédents correspondants.
Pour tirer un nombre aléatoire, nous utiliserons la fonction arc4random()
, qui renvoie un nombre aléatoire compris entre 0 et 4 294 967 295. Sauf que nous voulons un nombre de 4 chiffres, donc compris entre 1000 et 9999. Bref, on en est loin. Nous allons donc devoir ruser, grâce au modulo. Regardez le code suivant :
arc4random() % 9000 + 1000;
arc4random() % 9000
renvoie un nombre compris entre 0
et 8999
. En lui ajoutant 1000
, le nombre est compris entre 1000
et 9999
.
L'affichage du clavier est automatique lorsque le joueur clique dans la zone de saisie. Par contre, ce sera à vous de faire disparaître le clavier lorsque le joueur validera la saisie en appuyant sur la touche Retour
. Cette action sera accomplie en appelant la méthode resignFirstResponder
de la classe sender
.
Je suis sûr que vous êtes pressés de commencer. Imaginez un peu, votre première application ! Alors, n'attendez plus, commencez dès maintenant. Et soyez assurés que je ne serai pas loin de vous. Si vous avez une difficulté quelconque, reportez-vous à la correction qui suit. J'ai détaillé chaque étape de façon à ce qu'aucun blocage ne vous empêche d'arriver au bout du TP. Cependant, il est tout à fait normal de passer un long moment à réfléchir à ce que vous devez faire. Vous pouvez même vous aider d'une feuille blanche et d'un stylo en mettant par écrit vos idées.
Correction
J'espère que vous n'avez pas eu trop de problèmes dans ce TP. Voici ma correction, dans laquelle je passe en revue tous les points qui auraient pu « coincer ».
Création de l'application
Dans Xcode, sélectionnez Create a new Xcode project
dans la boîte de dialogue affichée au lancement du programme. Si aucune boîte de dialogue n'est affichée, lancez la commande New/New project
dans le menu File
. Dans la boîte de dialogue Choose a template for your new project
, choisissez Single View Application
puis cliquez sur Next
. Donnez le nom mastermind
à l'application, tapez test
dans la zone de texte Company Identifier
, cochez la case Use Storyboard
et cliquez sur Next
. Choisissez un dossier pour stocker l'application et validez en cliquant sur Create
.
Au bout de quelques instants, le squelette de l'application est créé.
Définition de l'interface
Sous le dossier mastermind
, cliquez sur l'entrée mainStoryboard.storyboard
dans la barre de navigation (volet gauche de l'application). Une interface désespérément vide est affichée dans la partie droite de la fenêtre (figure suivante). Rassurez-vous, nous allons très vite la remplir.

Dans la partie supérieure droite de la fenêtre (c'est-à-dire dans la barre d'outils), au-dessus du libellé View
, cliquez sur l'icône Hide or Show the utilities
(1) et cliquez sur l'icône Show the Object Library
(2) pour faire apparaître la bibliothèque, comme indiqué à la figure suivante.

Ajoutez deux Label
, un Text Field
, un Text View
et un Round Rect Button
à l'interface, puis redimensionnez-les pour obtenir une disposition semblable à la figure suivante.

Double-cliquez tour à tour sur les différents contrôles et insérez le texte spécifié dans le tableau suivant :
Contrôle | Texte |
---|---|
Premier Label | Saurez-vous trouver le nombre de quatre chiffres que j'ai choisi ? |
Deuxième Label | Tentez votre chance |
Text View | |
Round Rect Button | Choisir un autre nombre |
Le texte saisi dans le premier Label
est trop long. Comment l'afficher sur deux lignes ?
Si nécessaire, cliquez sur l'icône Show the Attributes inspector
dans la partie supérieure du volet gauche. Si vous cliquez sur le Label
, ses caractéristiques apparaissent dans le volet de l'inspecteur, comme sur la figure suivante. Sélectionnez Word Wrap
dans la liste déroulante Line Breaks
, tapez 2
dans la zone de texte Lines
et redimensionnez le contrôle pour obtenir l'effet recherché.

Pour supprimer le texte proposé par défaut dans le contrôle TextView
, cliquez dessus dans Interface Builder, sélectionnez le texte dans la zone Text
du volet de l'inspecteur, appuyez sur la touche Suppr, puis sur la touche Entrée du clavier.


Liaison des contrôles au code
Cachez la zone d'utilitaires en cliquant sur l'icône Hide or show the Utilities
(1) et affichez le code ViewController.h
en cliquant sur l'icône Show the Assistant editor
(2), comme montré à la figure suivante.

Vous allez maintenant relier les contrôles de l'interface au code.
Contrôle-glissez-déposez tour à tour les contrôles Text Field
et Text View
de l'interface jusqu'au volet de code. Donnez le nom saisie
au Text Field
, et le nom resultats
au Text View
.
Si vous avez suivi mes indications, le fichier ViewController.h
doit maintenant ressembler à ceci :
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UITextField *saisie;
@property (weak, nonatomic) IBOutlet UITextView *resultats;
@end
Pour terminer les liaisons, vous devez définir une action pour le contrôle Round Rect Button
. Contrôle-glissez-déposez ce contrôle juste avant l'instruction @end
. Au relâchement du bouton gauche de la souris, sélectionnez Action
dans la zone Connection
, tapez autrenombre
dans la zone de texte Name
et cliquez sur Connect
(figure suivante).

La ligne suivante est ajoutée au code :
(IBAction)autrenombre:(id)sender;
Sauvegardez votre projet avec la commande Save
dans le menu File
.
Juste histoire de souffler un peu, vous pouvez cliquer sur l'icône Run
dans la barre d'outils et savourer votre travail. Le résultat affiché devrait être semblable à la figure suivante.

Cliquez sur Stop
pour revenir à la dure réalité : vous devez maintenant écrire le code qui donnera vie à l'application !
Avant de commencer, cliquez sur ViewController.h
dans le volet de navigation et définissez la variable d'instance nombreChoisi
de type int
pour mémoriser le nombre choisi par le device. Le fichier d'en-têtes doit maintenant ressembler à ceci :
@interface ViewController : UIViewController
{
int nombreChoisi;
}
@property (weak, nonatomic) IBOutlet UITextField *saisie;
@property (weak, nonatomic) IBOutlet UITextView *resultats;
(IBAction)autrenombre:(id)sender;
@end
Je vous sens vraiment impatients de faire fonctionner l'application. Alors, passons sans plus attendre à l'écriture du code.
Écriture du code
Si nécessaire, affichez la zone de navigation en cliquant sur l'icône Hide or show the Navigator
, dans la partie droite de la barre d'outils, au-dessus du libellé View
.
Cliquez sur mastermindViewController.m
dans la zone de navigation. Le code généré par Xcode est de taille respectable. Il contient les différentes méthodes utilisées par l'application :
//Pour une meilleure lisibilité, j'ai supprimé les commentaires ajoutés automatiquement au début du fichier par Xcode
#import "ViewController.h"
@implementation ViewController
@synthesize saisie;
@synthesize resultats;
(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
(void)viewDidUnload
{
[self setSaisie:nil];
[self setResultats:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
(IBAction)autrenombre:(id)sender {
}
@end
En examinant les dernières lignes, vous reconnaissez certainement la partie déclarative liée à l'action sur le contrôle Round Rect Button
:
(IBAction)autrenombre:(id)sender {
}
Quelques lignes plus haut, la méthode viewDidLoad
va vous permettre d'initialiser l'application :
(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
Mais pourquoi serait-il nécessaire d'initialiser l'application me direz-vous ? Eh bien… pour choisir le nombre à découvrir !
Tirage aléatoire du nombre à découvrir
Ajoutez la ligne que nous avons vue plus haut, après [super viewDidLoad];
:
nombreChoisi = arc4random() % 9000 + 1000;
L'application sait maintenant tirer au hasard un nombre compris entre 1000
et 9999
.
Traitement suite à la proposition d'un nombre
Lorsque le joueur a saisi un nombre de quatre chiffres, il appuie sur la touche Return
pour valider la saisie. Le clavier doit alors disparaître de l'écran et le nombre entré doit être comparé au nombre à découvrir.
Pour ce faire, il est nécessaire de capturer l'événement « appui sur la touche Return
» et de le relier à une méthode afin d'effectuer les traitements nécessaires.
Dans un premier temps, commencez par définir la méthode saisieReturn
dans le fichier d'en-têtes. Cliquez sur ViewController.h
dans le volet de navigation et entrez cette ligne, juste au-dessus du @end
final :
(IBAction)saisieReturn :(id)sender;
Le fichier d'en-têtes doit maintenant ressembler à ceci :
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
{
int nombreChoisi;
}
@property (weak, nonatomic) IBOutlet UITextField *saisie;
@property (weak, nonatomic) IBOutlet UITextView *resultats;
(IBAction)autrenombre:(id)sender;
(IBAction)saisieReturn :(id)sender;
@end
Pour écrire le code qui efface le clavier de l'écran, cliquez sur ViewController.m
dans le volet de navigation et définissez la méthode saisieReturn
comme suit :
(IBAction)saisieReturn:(id)sender
{
[sender resignFirstResponder];
}
La méthode resignFirstResponder
efface le clavier. C'est aussi simple que cela !
N'essayez pas d'exécuter l'application : vous devez auparavant relier l'événement « appui sur la touche Retour
» à la méthode saisieReturn
.
Pour cela, sélectionnez l'entrée MainStoryboard.storyboard
dans la zone de navigation, affichez le volet des utilitaires en cliquant sur Hide or show the Utilities
dans la barre d'outils, puis cliquez sur Show the Connections inspector
, dans la partie supérieure. Cliquez sur le contrôle Text Field
dans la zone d'édition pour le sélectionner. Sous Sent Events
, repérez le rond à droite de l'événement Did End On Exit
et déplacez-le sur l'icône View Controller
, dans la partie inférieure de la zone d'édition. Au relâchement du bouton gauche de la souris, deux choix vous sont proposés : autreNombre
et saisieReturn
(figure suivante). Cliquez sur saisieReturn
. Ainsi, la méthode saisieReturn
sera exécutée lorsque l'utilisateur appuiera sur la touche Return
du téléphone.

Vous pouvez maintenant exécuter l'application et vérifier que l'appui sur la touche Return
dissimule le clavier.
Il est temps maintenant d'écrire le code relatif au traitement du nombre choisi par le joueur.
Cliquez sur ViewController.m
dans la zone de navigation et complétez la méthode saisieReturn
comme suit :
(IBAction)saisieReturn:(id)sender
{
[sender resignFirstResponder];
int bienPlace = 0;
int charIndex; //Index de boucle pour parcourir tous les caractères des chaînes à comparer
unichar testChar1, testChar2; //Les caractères à comparer : testChar1 dans le nombre proposé, testChar2 dans le nombre à trouver
for (charIndex = 0; charIndex < 4; charIndex++)
{
testChar1 = [saisie.text characterAtIndex:charIndex];
testChar2 = [[NSString stringWithFormat:@"%d", nombreChoisi] characterAtIndex:charIndex];
if (testChar1 == testChar2)
bienPlace++;
}
resultats.text = [NSString stringWithFormat:@"%@%@%d%@%@", saisie.text, @" : Bien placés : ", bienPlace, @"\r", resultats.text];
if (bienPlace == 4)
resultats.text = [NSString stringWithFormat:@"%@%d", @"Bravo, le résultat était ", nombreChoisi];
}
Examinons un peu ce code ensemble.
Comme il a été dit précédemment, la ligne 3 supprime le clavier de l'écran. Jusque-là, tout va bien !
Le bloc d'instructions suivant (lignes 4 à 13) compare le nombre entré par le joueur au nombre à découvrir. Les premières lignes déclarent plusieurs variables :
la variable entière
bienPlace
est définie et initialisée à0
:la variable entière
charIndex
est définie mais non initialisée :il en va de même pour les variables
unichar
testChar1
ettestChar2
:
int bienPlace = 0;
int charIndex;
unichar testChar1, testChar2;
La comparaison des quatre chiffres se fait dans une boucle for
, en utilisant la variable charIndex
comme index de boucle :
for (charIndex = 0; charIndex < 4; charIndex++)
À l'intérieur de la boucle, la première instruction s'intéresse à la saisie du joueur. Elle isole le caractère d'index charIndex
et le stocke dans la variable unichar testChar1
:
testChar1 = [saisie.text characterAtIndex:charIndex];
La deuxième instruction fait de même, mais sur le nombre tiré aléatoirement. L'instruction est plus complexe, car le nombre choisi aléatoirement est un int
et non un NSString
. Il est donc nécessaire de le convertir en NSString
avant de procéder à l'extraction :
testChar2 = [[NSString stringWithFormat:@"%d", nombreChoisi] characterAtIndex:charIndex];
Le premier message convertit l'int nombreChoisi
en un NSString
:
[NSString stringWithFormat:@"%d", nombreChoisi]
On extrait de l'objet ainsi obtenu le caractère qui se trouve à l'emplacement charIndex
(characterAtIndex:charIndex
) et on mémorise ce caractère dans la variable testChar2
(testChar2 =
).
Il ne reste plus qu'à comparer testChar1
à testChar2
et à incrémenter la variable bienPlace
si ces deux variables sont égales :
if (testChar1 == testChar2)
bienPlace++;
Une fois que les quatre chiffres ont été testés, il faut afficher le résultat dans le contrôle TextView
. C'est le rôle de l'instruction suivante :
resultats.text = [NSString stringWithFormat:@"%@%@%d%@%@", saisie.text, @" : Bien placés : ", bienPlace, @"\r", resultats.text];
On utilise pour cela une chaîne formatée ([NSString stringWithFormat: …]
). Examinons le format de la chaîne affichée :
%@%@%d%@%@
En comptant le nombre de %
, vous pouvez facilement déduire que cette chaîne est composée de cinq éléments. De gauche à droite, deux chaînes (%@
), un nombre décimal (%d
) et deux chaînes (%@
). Ces éléments sont les suivants :
la valeur saisie par le joueur,
saisie.text
;le texte « Bien placés : » ;
la valeur décimale
bienPlace
, convertie en une chaîne de caractères ;un saut de ligne
\r
;les différentes informations précédemment affichées dans le contrôle
TextView
.
La dernière instruction teste si la partie est terminée :
if (bienPlace == 4)
resultats.text = [NSString stringWithFormat:@"%@%d", @"Bravo, le résultat était ", nombreChoisi];
Si le nombre de caractères bien placés est égal à 4
(if (bienPlace == 4)
), cela signifie que le nombre entré est égal au nombre à découvrir. Dans ce cas, un message est affiché dans le contrôle TextView resultats
(resultats.text =
). Ici encore, nous utilisons une chaîne formatée ([NSString stringWithFormat: …]
). Comme vous pouvez le voir, le texte affiché est composé d'une chaîne et d'un nombre entier : le texte « Bravo, le résultat était », suivi du nombre à découvrir.
Tirage aléatoire d'un autre nombre
Pour terminer ce programme, il reste à écrire le code relatif à l'appui sur le bouton Choisir un autre nombre
. Rassurez-vous, cette tâche vous paraîtra on ne peut plus simple après ce que vous venez de vivre !
L'entrée ViewController.m
étant sélectionnée dans le volet de navigation, déplacez-vous dans la partie inférieure du code et complétez la méthode autrenombre
comme suit :
(IBAction)autrenombre:(id)sender
{
nombreChoisi = arc4random() % 9000 + 1000;
resultats.text = [NSString stringWithFormat:@"%@", @"J'ai choisi un nouveau nombre\r"];
}
La première instruction est identique à celle qui a déjà été utilisée pour tirer un nombre aléatoire. Elle choisit un nombre compris entre 1000
et 9999
et le stocke dans la composante text
de l'objet label nombreChoisi
:
nombreChoisi = arc4random() % 9000 + 1000;
La deuxième instruction affiche le message « J'ai choisi un nouveau nombre » dans le contrôle TextView
:
resultats.text = [NSString stringWithFormat:@"%@", @"J'ai choisi un nouveau nombre\r"];
L'application est entièrement fonctionnelle. Cliquez sur Run
et amusez-vous bien !
Le code complet
Je vous mets ici le code complet de l'application.
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
{
int nombreChoisi;
}
@property (weak, nonatomic) IBOutlet UITextField *saisie;
@property (weak, nonatomic) IBOutlet UITextView *resultats;
(IBAction)autrenombre:(id)sender;
(IBAction)saisieReturn :(id)sender;
@end
ViewController.m
#import "ViewController.h"
@implementation ViewController
@synthesize saisie;
@synthesize resultats;
(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
(void)viewDidLoad
{
[super viewDidLoad];
nombreChoisi = arc4random() % 9000 + 1000;
}
(void)viewDidUnload
{
[self setSaisie:nil];
[self setResultats:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
(IBAction)autrenombre:(id)sender
{
nombreChoisi = arc4random() % 9000 + 1000;
resultats.text = [NSString stringWithFormat:@"%@", @"J'ai choisi un nouveau nombre\r"];
}
(IBAction)saisieReturn:(id)sender
{
[sender resignFirstResponder];
int bienPlace = 0;
int charIndex;
unichar testChar1, testChar2;
for (charIndex = 0; charIndex < 4; charIndex++)
{
testChar1 = [saisie.text characterAtIndex:charIndex];
testChar2 = [[NSString stringWithFormat:@"%d", nombreChoisi] characterAtIndex:charIndex];
if (testChar1 == testChar2)
bienPlace++;
}
resultats.text = [NSString stringWithFormat:@"%@%@%d%@%@", saisie.text, @" : Bien placés : ", bienPlace, @"\r", resultats.text];
if (bienPlace == 4)
resultats.text = [NSString stringWithFormat:@"%@%d", @"Bravo, le résultat était ", nombreChoisi];
}
@end