iOS & Modal Partial Curl & SQLite

Pour poursuivre avec mon précédent billet (ici), j’ai eu l’envie de tester SQLite avec iOS.

Qu’est-ce que SQLite ?

En gros, c’est une base de données légère intégrée au programme stockée dans un fichier.

Plus d’informations sur le site officiel et sur wikipedia.

L’intérêt est donc d’avoir peu de données à mettre dans notre base embarquée car une app trop lourde est souvent rédhibitoire pour une installation sur iPhone.

Je conseillerai de ne pas dépasser les 100 ko pour rester cohérent.

Comment fait-on alors ?

Et bien par chance, SQLite est déjà installée sous Mac !

Pour vérifier, tapez dans le terminal :

sqlite3 -version

Nous allons donc créer une base de données tuto.db avec une table Objet ayant pour champs num et forme, toujours dans le terminal :


sqlite3 tuto.db

puis

[sql]
<sqlite> CREATE TABLE Objet(num integer primary key, forme varchar(25));
<sqlite> INSERT INTO Objet(num, forme) VALUES(1,cercle);
<sqlite> INSERT INTO Objet(num, forme) VALUES(1,carre);
<sqlite> INSERT INTO Objet(num, forme) VALUES(1,triangle);
[/sql]

Si vous voulez encore vous amusez avec SQLite, tapez .help pour afficher les commandes sinon tapez .quit ou .exit.

Et voilà, nous avons un joli fichier tuto.db à l’endroit où vous avez ouvert le terminal (généralement votre répertoire personnel).

Ouvrez votre projet PageTrick (cf lien plus haut) et glissez/déposez-y votre fichier.
Ajoutez-y également la bibliothèque libsqlite3.0.dylib :
– cliquez sur votre projet dans le menu contextuel
– cliquez sur Targets puis sur Build Phases
– cliquez sur le + du sous-menu Link Binaries With Library
– dans la barre de recherche tapez libsqlite
– déroulez les résultats vous devriez avoir libsqlite3.0.dylib (ne vous trompez pas il y en a deux, l’autre c’est libsqlite3.dylib)
– c’est bon !

Génial et maintenant comment s’en sert-on ? C’est à ce moment que l’on doit faire un choix, en effet SQLite étant une bibliothèque écrite en C, il va falloir insérer des appels de fonction C dans notre joli code Objective-C… pas glop (personnellement) MAIS on peut utiliser un petit framework (2 classes) créer par Th30z et disponible sur GitHub.

Dézippez l’archive et glissez/déposez Sqlite.h et Sqlite.m dans votre projet.

Attention si vous êtes dans un projet avec ARC (Automatic Reference Counting) activé – il faut modifier un peu le Sqlite.m mais c’est trois fois rien :
– supprimez tous les autorelease, retain, release qui traînent
– remplacez la ligne 32 par : [code lang= »objc » gutter= »false »]return (__bridge NSString *)uuidStringRef;[/code]

Plus de détails sur ce cast sur clang.llvm.org.

Maintenant vous pouvez utiliser l’objet Sqlite dans votre code.

Dans votre storyboard, déposer un UITableViewController et faîtes un segue depuis un bouton « clickSQLite » (le sosie du bouton « click » du PageTrickController) vers lui et n’oubliez pas de donner un identifiant au segue.

Voici ce que vous devriez avoir modulo les préférences esthétiques de chacun :

Créez une nouvelle classe (UIViewController class) héritant de UITableViewController et appelez la TablePageCurlController par exemple.

Ensuite on reprend le même principe de délégation vu dans mon billet précédent sauf que l’on va créer un fichier pour le protocole genre PageCurlDelegate.h :

[objc]
#import &lt;UIKit/UIKit.h&gt;
@protocol PageCurlDelegate -(void)dismissWithData:(NSString *)data;
@end
[/objc]
[objc]
#import &lt;UIKit/UIKit.h&gt;;
#import &quot;PageCurlDelegate.h&quot;;

@interface TablePageCurlController : UITableViewController
@property(nonatomic, weak) id&lt;PageCurlDelegate&gt; delegate;
@property(nonatomic) NSInteger nbRow;
@property(nonatomic, strong) NSArray *objects;
@end
[/objc]

on n’oublie pas de synthétiser !

[objc]
@synthesize delegate = _delegate, nbRow = _nbRow, objects = _objects;
[/objc]

on complète les méthodes de notre contrôleur :

[objc]
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _nbRow;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @&quot;myCell&quot;;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

NSDictionary * objet = [_objects objectAtIndex:indexPath.row];
id num = [objet objectForKey:@&quot;num&quot;];
if([num isKindOfClass:[NSNumber class]]){
if([num intValue] == indexPath.row+1){
cell.textLabel.text = [objet objectForKey:@&quot;forme&quot;];
}
}
return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.delegate dismissWithData:[tableView cellForRowAtIndexPath:indexPath].textLabel.text];
}
[/objc]

puis dans PageTrickController, on ajoute une propriété tablePage de type TablePageCurlController et on modifie :

[objc]
// (dans l'interface) ajout dont je parlais
@property(nonatomic, strong) TablePageCurlController * tablePage;

// (dans l'implémentation)
-(void)dismissWithData:(NSString *)data{

NSLog(@&quot;%@&quot;, data);

[_page dismissModalViewControllerAnimated:YES];
_page = nil;
[_tablePage dismissModalViewControllerAnimated:YES];
_tablePage = nil;
}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:@&quot;tableModalCurl&quot;]){
_tablePage = segue.destinationViewController;
_tablePage.delegate = self;

//création de l'objet Sqlite
Sqlite *sqlite = [[Sqlite alloc] init];

//récupération de la base de données
NSString *dbPath = [[NSBundle mainBundle] pathForResource:@&quot;obj&quot; ofType:@&quot;db&quot;];

//ouverture de la connexion vers la base
if(![sqlite open:dbPath]) return;
NSArray *objs = [sqlite executeQuery:@&quot;SELECT * FROM Objet&quot;];

//fermeture de la connexion
[sqlite close];
_tablePage.nbRow = objs.count;
_tablePage.objects = objs;

}else if([segue.identifier isEqualToString:@&quot;modalCurl&quot;]){
_page = segue.destinationViewController;
_page.delegate = self;
}
}
}
[/objc]

Alors heureux ?
« Aaaargh mais nan, on ne voit pas la tableView !!!! »

Ah oui, c’est vrai la tableView est en partie masquée par l’animation et du coup c’est moche.
Rajoutez ceci dans le viewDidAppear de votre TablePageCurlController :

[objc]
-(void)viewDidAppear:(BOOL)animated {

[super viewDidAppear:animated];
[self.tableView setContentOffset:CGPointMake(0, -self.tableView.frame.size.height/4) animated:YES];
//[self.tableView reloadData]; // pas nécessaire : si vous avez des soucis de sélection
//[self.view setNeedDisplay]; // pas nécessaire : faîtes plutôt un clean du projet d'abord
}
[/objc]

Et voilà deux belles animations pour le prix d’une !