Pour ce 14ème tutoriel, nous allons voir comment lire et écrire dans une base de données grâce à sqlite.
Afin d’essayer de rendre ce tutoriel utile au plus grand nombre, j’ai décidé de montrer comment enregistrer le score d’un joueur puis afficher les trois meilleurs dans des labels.
Nous obtiendrons ceci :
Pour expliquer rapidement, on peut entrer le nom du joueur dans un textfield, générer un score avec un bouton puis enregistrer et actualiser les meilleurs scores.
C’est ce fichier qui va contenir physiquement la base de données. On pourra ensuite le lire, le trier et l’éditer.
Pour le créer, il faut utiliser le Terminal (spotlight->”terminal”). Placez-vous dans le dossier désiré et pour créer le fichier voici les commandes nécessaires :
//création du fichiersqlite3 sqlDatabase.sql//création de la Base de Données (BDD)CREATE TABLE score ( id INTEGER PRIMARY KEY, nom VARCHAR(50), scoreValue INT);INSERT INTO score (nom, scoreValue) VALUES ('iPodishima', '5');INSERT INTO score (nom, scoreValue) VALUES ('Heyfeel', '4');INSERT INTO score (nom, scoreValue) VALUES ('Aurel', '3');INSERT INTO score (nom, scoreValue) VALUES ('Bidou', '2');
Il faut maintenant mettre ce fichier dans les ressources d’un nouveau projet Xcode View-Based application nommé Score. Faire “copy items into destination group’s folder”.
Tout d’abord il faut importer le framework sqlite qui n’est pas vraiment aussi simple que les autres à ajouter : Faire “add->existing frameworks” ensuite avec le Finder cherchez un fichier qui se nomme libsqlite3.0.dylib. Si vous en trouvez plusieurs, le bon est celui qui se trouve ici :
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/lib/
Il suffit ensuite de l’ajouter.

Les déclarations de l’interface Builder dans ScoreViewController.h
@interface ScoreViewController : UIViewController <UITextFieldDelegate> {IBOutlet UILabel *lblScore;IBOutlet UILabel *mScoreUn;IBOutlet UILabel *mScoreDeux;IBOutlet UILabel *mScoreTrois;IBOutlet UITextField *textField;}
ScoreViewController.m
int scoreI=0;-(BOOL)textFieldShouldReturn:(UITextField *)leTextField {if (leTextField == textField ){[textField resignFirstResponder];}return YES;}-(IBAction)incrementScore:(id)sender{scoreI++;//Affichage du scorelblScore.text = [[NSString alloc] initWithFormat:@"Score = %d",scoreI] ;}-(IBAction)incrementScore:(id)sender{scoreI++;//Affichage du scorelblScore.text = [[NSString alloc] initWithFormat:@"Score = %d",scoreI] ;}
Il faut commencer par créer une nouvelle classe “NSObject subclass” nommée Score.
Cette classe va nous permettre de créer un objet Score qui contiendra les valeurs de la BDD.
Score.h
#import <Foundation/Foundation.h>#import <sqlite3.h>@interface Score : NSObject {NSInteger primaryKey;NSString *nom;NSInteger scoreValue;}@property (assign, nonatomic, readonly) NSInteger primaryKey;@property (nonatomic, retain) NSString *nom;@property (assign, nonatomic, readonly) NSInteger scoreValue;-(id)initWithName:(NSString *)n scoreValue:(NSInteger )s;@end
Score.m
#import "Score.h"@implementation Score@synthesize nom,scoreValue,primaryKey;-(id)initWithName:(NSString *)n scoreValue:(int )s {self.nom = n;scoreValue = s;return self;}@end
Il faut maintenant créer une nouvelle classe NSObject subclass qui va permettre d’administrer la BDD. Vous pouvez la nommer SQLmanager : je me suis servi du tutoriel disponible ici auquel j’ai ajouté l’écriture comme on le verra par la suite.
SQLmanager.h
#import <Foundation/Foundation.h>#import <sqlite3.h> // Import du framework sqlite#import "Score.h" // Import de l'objet Score@interface SQLManager : NSObject {// Variables de la Base de DonnéesNSString *databaseName;NSString *databasePath;// Tableau de ScoresNSMutableArray *scores; }@property (nonatomic, retain) NSMutableArray *scores;-(id) initDatabase;-(void) checkAndCreateDatabase;-(void) readScoresFromDatabase;@end
SQLmanager.m
#import "SQLManager.h"@implementation SQLManager@synthesize scores;-(id) initDatabase{//On définit le nom de la base de donnéesdatabaseName = @"sqlDatabase.sql";// On récupère le chemin NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);NSString *documentsDir = [documentPaths objectAtIndex:0];databasePath = [documentsDir stringByAppendingPathComponent:databaseName];return self;}-(void) checkAndCreateDatabase{// On vérifie si la BDD a déjà été sauvegardée dans l'iPhone de l'utilisateurBOOL success;// Crée un objet FileManagerCreate qui va servir à vérifer le status// de la base de données et de la copier si nécessaireNSFileManager *fileManager = [NSFileManager defaultManager];// Vérifie si la BDD a déjà été créée dans les fichiers system de l'utilisateursuccess = [fileManager fileExistsAtPath:databasePath];// Si la BDD existe déjà "return" sans faire la suiteif(success) return;// Si ce n'est pas le cas alors on copie la BDD de l'application vers les fichiers système de l'utilisateur// On récupère le chemin vers la BDD dans l'applicationNSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];// On copie la BDD de l'application vers le fichier systeme de l'application[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];[fileManager release];}-(void) readScoresFromDatabase {// Déclaration de l'objet databasesqlite3 *database;// Initialisation du tableau de scorescores = [[NSMutableArray alloc] init];// On ouvre la BDD à partir des fichiers systèmeif(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {// Préparation de la requête SQL qui va permettre de récupérer les objets score de la BDD//en triant les scores dans l'ordre décroissantconst char *sqlStatement = "select * from score ORDER BY scoreValue DESC";//création d'un objet permettant de connaître le status de l'exécution de la requêtesqlite3_stmt *compiledStatement;if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {// On boucle tant que l'on trouve des objets dans la BDDwhile(sqlite3_step(compiledStatement) == SQLITE_ROW) {// On lit les données stockées dans le fichier sql// Dans la première colonne on trouve du texte que l'on place dans un NSStringNSString *aName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];// Dans la deuxième colonne on récupère le score dans un NSIntegerNSInteger aScore = sqlite3_column_int(compiledStatement, 2);// On crée un objet Score avec les pramètres récupérés dans la BDDScore *score = [[Score alloc] initWithName:aName scoreValue:aScore];// On ajoute le score au tableau[scores addObject:score];[score release];}}// On libère le compiledStamenent de la mémoiresqlite3_finalize(compiledStatement);}//On ferme la BDDsqlite3_close(database);}@end
Nous allons maintenant voir comment utiliser ce code en réalisant l’affichage des trois meilleurs scores.
Dans le ScoreViewController.m
#import "ScoreViewController.h"#import "ScoreAppDelegate.h"#import "Score.h"#import "SQLManager.h"@implementation ScoreViewController- (void)viewDidLoad {[super viewDidLoad];// initialisation de la BDDsqlManager = [[SQLManager alloc] initDatabase];//Vérification et création de la BDD[sqlManager checkAndCreateDatabase];//Lecture des scores et création du tableau[sqlManager readScoresFromDatabase];//On appelle l'affichage dans les labels[self afficherScore];}-(void)afficherScore{//On affiche les trois premiers scores du tableau//création d'un objet score qui est égal au premier du tableauScore *score = (Score *)[sqlManager.scores objectAtIndex:0];//on
écrit dans le label le nom et le scoreValue du premier Score du
tableau, c'est le meilleur puisqu'on a trié dans l'ordre décroisantmScoreUn.text = [score.nom stringByAppendingString: [[NSString alloc] initWithFormat:@"\t \t %d points", score.scoreValue]];score = (Score *)[sqlManager.scores objectAtIndex:1];//même chose pour le deuxième et le troisième ScoremScoreDeux.text = [score.nom stringByAppendingString: [[NSString alloc] initWithFormat:@"\t \t %d points", score.scoreValue]];score = (Score *)[sqlManager.scores objectAtIndex:2];mScoreTrois.text = [score.nom stringByAppendingString: [[NSString alloc] initWithFormat:@"\t \t %d points", score.scoreValue]];}
Dans ScoreViewController.h il faut déclarer un SQLManager :
SQLManager *sqlManager;
Il faut ajouter une méthode au SQLManager
- (void)insertIntoDatabase:(Score*)newScore {//initialisiation de la BDD[self initDatabase];//Vérification de la BDD[self checkAndCreateDatabase];// Déclaration de l'objet databasesqlite3 *database;// On ouvre la BDD à partir des fichiers systèmeif(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {// Préparation de la requête SQL qui va permettre d'ajouter un score à la BDD NSString *sqlStat = [[[NSString alloc] initWithFormat:@"INSERT INTO score (nom, scoreValue) VALUES ('%@', '%d');",newScore.nom, newScore.scoreValue] autorelease];//Ici c'est pas génial comme méthode donc si vous trouvez mieux je suis prenneurconst char *sqlStatement = [sqlStat cStringUsingEncoding : [NSString defaultCStringEncoding]];//On utilise sqlite3_exec qui permet très simplement d'exécuter une requète sur la BDDsqlite3_exec(database, sqlStatement,NULL,NULL,NULL);}sqlite3_close(database);}
Et on ajoute l’appel dans le ScoreViewController
-(IBAction)saveScore:(id)sender{Score *score = [[Score alloc] initWithName:textField.text scoreValue:scoreI];[sqlManager insertIntoDatabase:score];[sqlManager readScoresFromDatabase];[self afficherScore];}
Si ça fonctionne “Well Done” sinon vous pouvez vous aider des sources et venir poser vos questions sur le forum.