Tu veux promouvoir ton application ici ? Ce service est gratuit pour le moment alors profites en !


Tutoriel n°5 : Que diriez-vous de quelques tableaux ? — V2

Bonjour !


Bienvenue dans ce cinquième tutoriel version 2 !

Quelques changements par rapport à la version 1 notamment au niveau de la gestion du fichier texte qui n'était pas très logique. Et comme  d'habitude, ce tuto est adapté à la dernière version de XCode et l'OS 3.1.2 !



Aujourd'hui, nous allons apprendre à nous servir des Tableaux. Il en existe deux sortes : les objets NSArray et NSMutableArray. La principale différence est simple : un NSArray a une taille fixe, tandis qu'un NSMutableArray n'a pas de taille définie. C'est-à-dire qu'on pourrait lui ajouter des éléments "indéfiniment".

Pour la petite histoire, on parle de tableaux "statiques" pour les NSArray, et "dynamiques" pour les NSMutableArray.

Pour les tableaux, étant donné que l'Objective-C vient du C, vous pouvez déclarer des tableaux comme ceci


// petit rappel : 
char tableau[10]; //tableau de 10 caractères
int tableau2[10][10]; // tableau bidimensionnel d'entiers soit 100 entiers

Du coup, ce type de déclaration s'apparente aux NSArray, car leur taille est fixe.

Nous allons donc nous intéresser aux NSMutableArray :

1) Créons notre projet ainsi que l'interface

Créez un projet "Window-based application" que vous nommerez iPuPArray

Commencez par créer une interface comme dans le tutoriel n°3.

La première astuce du tutoriel : faites un tour ici sous IB

http://www.ipup.fr/forum/userimages/Capture-d-ecran-2010-01-23-a-13.28.51.png



Vous verrez que vous pouvez ajouter des lignes horizontales et verticales rouges pour vous aider à agencer vos objets.

2) Ecrivons un peu de code ...

Une fois tout relié et la classe écrite dans XCode, nous allons modifier les fichiers "iPuPView.m" et "iPuPView.h". Double-cliquez sur "iPuPView.m".

La deuxième astuce du jour : en haut à droite de votre fenêtre, vous allez trouver une petite icône ressemblant à ceci :

http://www.ipup.fr/forum/userimages/Capture-d-ecran-2010-01-23-a-13.30.54.png



Cliquez-dessus... wink vous passez au header! Recliquez... tongue retour au .m!

Bon, il suffit, on n'est pas là pour jongler entre les fenêtres, vous voulez faire des tableaux ou pas? roll

Voici ce que nous allons faire : créer une méthode qui permettra de créer un tableau et l'exporter dans un fichier texte .txt. Nous la nommerons "createAnArrayAndExportToTextFile" ... Bon, cela fait des noms à rallonge, mais vous savez de quoi vous parlez après big_smile

Ensuite, nous allons créer une méthode qui se chargera d'afficher le contenu du tableau dans le label. Nous verrons la description de la méthode plus tard...

Commençons par la méthode "createAnArrayAndExportToATextFile"

Tout d'abord, écrivez ceci dans l'implementation de iPuPView (Rappel : dans le "iPuPView.m")

// Permet de créer un tableau et de l'exporter dans un fichier texte
- (BOOL) createAnArrayAndExportToTextFile {

}

Nous allons maintenant créer un NSMutableArray en l'initialisant avec des objets NSString :


// créé un NSMutableArray et l'initialise avec @"Object 1", @"Object 2", @"Object 3"
NSMutableArray *iPuPArray = [[NSMutableArray alloc] initWithObjects:@"Object 1", @"Object 2", @"Object 3",nil];

N'oubliez pas de terminer par nil...

Il faut ensuite écrire ce tableau dans le fichier "iPuP.txt"

Attention, il faut bien utiliser le dossier "Documents" de l'application dans votre iPhone. C'est le seul endroit où votre application aura le droit d'écrire.

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
    
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"nomFichier.txt"];

D'où :

Un peu de culture, mais pas obligatoire : wink



Si "atomically" est à NO, cela signifie que vous écrivez directement dans le fichier "iPuP.txt". Si il est à YES, l'écriture se fait déjà dans un fichier temporaire, puis dans le fichier texte.
Ok... "Si tu veux" me direz-vous. Eh bien, le fait de mettre à YES permet de ne pas corrompre le fichier texte si votre appli crashe pendant l'écriture... voilà cool




Très bien! vous vous en doutez, il faut maintenant faire un ........... pour iPuPArray ? ............. un ...... release Oui! N'oubliez jamais : après un alloc, un release! Ici, nous utilisons un mécanisme particulier : l'autorelease. Lisez la "fiche mémoire" !

// permet de libérer automatiquement de la mémoire iPuPArray
    [iPuPArray autorelease];

Récapitulons : votre méthode ressemble à ça :

// Permet de créer un tableau et de l'exporter dans un fichier texte
// Permet de créer un tableau et de l'exporter dans un fichier texte
- (BOOL) createAnArrayAndExportToTextFile {
    
    // créé un NSMutableArray et l'initialise avec @"Object 1", @"Object 2", @"Object 3"
    NSMutableArray *iPuPArray = [[NSMutableArray alloc] initWithObjects:@"Object 1", @"Object 2", @"Object 3",nil];
    
    // exporte le contenu du tableau dans un fichier txt
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"iPuP.txt"];
    
    // permet de libérer automatiquement de la mémoire iPuPArray
    [iPuPArray autorelease];
    
    // ecrit dans le fichier et retourne un booléen
    return [iPuPArray writeToFile:filePath atomically:YES] && filePath;
}

Ok, <pomme + s> et cliquez sur notre bouton du jour :

http://www.ipup.fr/forum/userimages/Capture-d-ecran-2010-01-23-a-13.30.54.png

. Dans le header, "iPuPView.h", écrivez ceci

- (BOOL) createAnArrayAndExportToTextFile;

Euh, pourquoi ce n'est pas -(void) maMethode, mais -(BOOL) maMethode ?? !

Tout simplement parce que nous souhaitons savoir si l'écriture dans le fichier s'est bien passée et si le fichier existe bien.
Or la doc nous dit :

Documentation Xcode

writeToFile:atomically:
Writes the contents of the receiver to a file at a given path.

- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag

Parameters
path
The path at which to write the contents of the receiver.

If path contains a tilde (~) character, you must expand it with stringByExpandingTildeInPath before invoking this method.

flag
If YES, the array is written to an auxiliary file, and then the auxiliary file is renamed to path. If NO, the array is written directly to path. The YES option guarantees that path, if it exists at all, won’t be corrupted even if the system should crash during writing.

Return Value
YES if the file is written successfully, otherwise NO.


Discussion
If the receiver’s contents are all property list objects (NSString, NSData, NSArray, or NSDictionary objects), the file written by this method can be used to initialize a new array with the class method arrayWithContentsOfFile: or the instance method initWithContentsOfFile:. This method recursively validates that all the contained objects are property list objects before writing out the file, and returns NO if all the objects are not property list objects, since the resultant file would not be a valid property list.

Availability
Available in iPhone OS 2.0 and later.
See Also
– initWithContentsOfFile:
Declared In
NSArray.h



Donc, si le tableau est bien écrit, la méthode retournera YES !

Deuxième étape : afficher un élément du tableau dans un label...

Mais il faut bien comprendre comment accéder aux données de votre tableau.
En fait, vos objets dans le tableau sont indexés.
En C, rappelez-vous, vous accédiez aux éléments de "tableau" de la sorte :

int tableau[3];
int element;
tableau[0]=4;
tableau[1]=8;
tableau[2]=16;

element = tableau[0]; // element sera donc égal à la première valeur de votre tableau soit 4

Avec un NSArray, c'est la même chose, on accède à l'élément i avec "atIndex:i"

Revenez à votre .m et écrivons notre méthode displayElementOfArray :

Nous allons faire passer des paramètres à cette méthode. Soyez attentifs à l'écriture.


// permet d'afficher l'élément à l'index "index" d'un tableau passé en paramètre dans un label
- (void) displayElementOfArray:(NSArray *) monTableau forIndex:(NSInteger) index {
    
}

Pour afficher l'élément de l'index dans votre label :

//affiche le texte de l'objet du tableau à l'index spécifié
monLabel.text = [monTableau objectAtIndex:index];

// Attention : ici, si index est plus grand que la taille de notre tableau, l'appli plante.
// On peut implémenter une fonction gérant "si index>taille de monTableau alors on ne fait rien sinon on affiche"

N'oubliez pas de mettre la fonction dans le .h.

Finalement,

// permet d'afficher l'élément à l'index "index" d'un tableau passé en paramètre dans un label
- (void) displayElementOfArray:(NSArray *) monTableau forIndex:(NSInteger) index {

    if(index < [monTableau count]) 
    {
        NSLog(@"L'index %d est ok, on affiche dans le label", index);
        //affiche le texte de l'objet du tableau à l'index spécifié
        labeliPuP.text = [monTableau objectAtIndex:index];
    }
    else
    {
        NSLog(@"L'index %d est en dehors du tableau, erreur", index);
        labeliPuP.text = @"Erreur";
    }
    [labeliPuP sizeToFit];
}

3) Utilisons tout ça

Pour terminer, il faut créer ce tableau et afficher un élément. Pour l'instant, nous n'avons qu'écris les méthodes permettant de le faire.

Pour cela, nous allons utiliser encore awakeFromNib. Sachez juste que nous utilisons cette méthode pour le besoin du tutoriel. Nous souhaitons simplement vous montrer comment fonctionne les tableaux sans gérer d'événements.

- (void) awakeFromNib {
    
    [labeliPuP setTextColor:[UIColor colorWithRed:200.0/255.0 green:250.0/255.0 blue:255.0/255.0 alpha:1.0]];
    [labeliPuP setFont:[UIFont fontWithName:@"Zapfino" size:19.0]];
    
    // on recherche le filePath
    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,  YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    
    NSString  *filePath = [documentsDirectory stringByAppendingPathComponent:@"iPuP.txt"];
    
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSData *data = [fileManager contentsAtPath:filePath];
    
    
    BOOL peutLireDansLeFichier = NO;
    if(!data)
    {
        // le fichier iPuP.txt ne contient aucune donnée, il nous faut donc le remplir pour les besoins du tuto :
        //crée un tableau et l'exporte dans un fichier texte
        BOOL success = [self createAnArrayAndExportToTextFile];
        NSLog(@"Création d'un array = succès ? %@", success ? @"YES" : @"NO");
        peutLireDansLeFichier = success;

    }
    else 
    {
        // le fichier contient déjà des données, donc on peut lire sans souci dedans !
        peutLireDansLeFichier = YES;
    }
    
    if(peutLireDansLeFichier)
    {
        NSLog(@"Le fichier contient des données, on peut lire dedans");
        //création d'un NSArray qui lira dans le fichier Texte (initialisation avec
        // le contenu d'un fichier : iPuP.txt dont nous avons spécifié le chemin avec filePath
        NSArray *iPuPArray = [[NSArray alloc] initWithContentsOfFile:filePath];
        
        //appel de la fonction permettant l'affichage dans le label
        [self displayElementOfArray:iPuPArray forIndex:3];
        
        // libére la mémoire
        [iPuPArray release];
    }
    
}

Sauvez et lancez. Vous obtenez ceci :

http://www.ipup.fr/forum/userimages/Capture-d-ecran-2010-01-23-a-13.56.14.png



Vous avez bien affiché le troisième élément de votre tableau! Ouf... tongue
Amusez à vous changer la valeur de l'index lors de l'appel de displayElementOfArray.

Voilà, vous savez comment utiliser un tableau!


Ici, il faut bien remarquer que je souhaite vous montrer le mécanisme d'écriture/lecture dans un fichier texte.
En fait, il faudrait dans l'application pouvoir ajouter des éléments dans un tableau et ensuite créer si il n'existe pas un fichier .txt où l'on pourra écrire ce tableau.
Si le fichier texte existe, il faut alors simplement le mettre à jour.
D'où le chapitre "Pour aller encore plus loin" vous permettant de modifier ce tableau !



4) Allons plus loin ...

Vous pouvez ajoutez un élément dans votre NSMutableArray de la manière suivante :


// ajoute un élément dans le tableau
[iPuPArray addObject:@"iPuP"];

soit

// Permet de créer un tableau et de l'exporter dans un fichier texte
- (BOOL) createAnArrayAndExportToTextFile {
    
    // créé un NSMutableArray et l'initialise avec @"Object 1", @"Object 2", @"Object 3"
    NSMutableArray *iPuPArray = [[NSMutableArray alloc] initWithObjects:@"Object 1", @"Object 2", @"Object 3",nil];
    
    // ajoute un élément dans le tableau
    [iPuPArray addObject:@"iPuP"];
    
    // exporte le contenu du tableau dans un fichier txt
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    
    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"iPuP.txt"];
    
    // permet de libérer automatiquement de la mémoire iPuPArray
    [iPuPArray autorelease];
    
    // ecrit dans le fichier et retourne un booléen
    return [iPuPArray writeToFile:filePath atomically:YES] && filePath;
}

Maintenant, affichez l'élément 4 (atIndex:3  (4-1))

//appel de la méthode permettant l'affichage dans le label
[self displayElementOfArray:iPuPArray forIndex:3];

Vous obtenez

http://www.ipup.fr/forum/userimages/Capture-d-ecran-2010-01-23-a-14.02.50.png



Pour aller encore plus loin...

Si vous utilisiez des tableaux bidimensionnels, vous pourriez accéder à l'élément de la colonne j et ligne i, en représentation matricielle, par "tableau [i][j]". Rappelez vous, les lignes et colonnes commencent à 0 et pas à 1.

Vous pouvez continuer à utiliser des NSArray ou NSMutableArray qui sont des tableaux à une dimension de la manière suivante : connaissant le nombre de colonnes m de votre tableau bidimensionnel, l'élément de la ligne i et colonne j est accessible à l'index suivant : k=i*m+j.
Cela peut se révéler utile si vous souhaitez mettre des objets dans un tableau, plus compliqués qu'un NSString.

sources




Petit exercice

Ajouter un textField à votre view, autoriser les interactions pour cette vue si besoin (cocher "User Interaction Enabled")

http://www.ipup.fr/forum/userimages/Image-39.jpg



Il vous faudra aller chercher dans les propriétés du textField pour que "Enter" soit "Done", mettre par défaut un clavier numérique, ...

Aide et correction


Voilà, à bientôt dans un prochain tutoriel!

Ipodishima

Copyright © 2009 - ipup.fr • création de Jérémy Lagrue • design de Loann Fraillon • contact