XCode: SQLite en 5 minutos



Esta es la continuación de éste otro post de introducción a SQLite. En esta ocasión vamos a utilizar la base de datos creada en una App para iPhone.

Aún no tengo ningún post de como crear una App en iOS desde cero, pero si os interesa dejad un comentario. Así que vamos a suponer que sabéis como crear un simple proyecto. Además vamos a utilizar ARC, que para quien no lo sepa, en pocas palabras significa que nos podemos olvidar de los "alloc" y los "dealloc" de Objective-C. Si no tocáis ningún ajuste y utilizáis una versión medianamente moderna de XCode, los proyectos utilizan ARC por defecto.

Crear el proyecto

Creamos un nuevo proyecto en XCode que podemos llamar Highscores. Vamos a crear un proyecto con una sola vista y una tabla para mostrar los datos.




Añadimos en "Frameworks" la librería "libsqlite3.dylib".

Modelo

Creamos algunas entradas más en el archivo de base de datos del post anterior ("ABC.sqlite") y lo añadimos al proyecto (clic derecho y "Add Files to X" dejando marcada la casilla de "Copy items into destination group..."):



Creamos la clase "Puntuacion" donde guardaremos los datos. Con ARC y las últimas versiones de XCode y de iOS, no hace falta que toquemos el ".m"para añadir las sentencias "@synthesize" ya que se generan de forma automática. Añadimos a Puntuacion.h:

#import <Foundation/Foundation.h>

@interface Puntuacion : NSObject

@property NSNumber *mode;
@property NSString *name;
@property NSNumber *value; @end

Creamos la clase "BaseDeDatos". Esta clase será un Singleton que nos permitirá comunicarnos con la base de datos desde cualquier punto de la App. El archivo "BaseDeDatos.h" debería de quedar tal que así:

#import <Foundation/Foundation.h>
#import <sqlite3.h>

@interface BaseDeDatos : NSObject

+(id)sharedInstance;

-(NSArray*)puntuacionesOrdenadasAscendentemente;
-(NSArray*)puntuacionesOrdenadasPorNombre;
-(NSArray*)puntuacionesOrdenadasPorModo;

@end

Y "BaseDeDatos.m" tal que así:

#import "BaseDeDatos.h"

#import "Puntuacion.h"

@interface BaseDeDatos()

@property sqlite3 *database;

-(NSArray*)performQuery:(NSString*)query;

@end

@implementation BaseDeDatos

static BaseDeDatos *_sharedInstance;

+(id)sharedInstance {
  if (_sharedInstance == nil) {
    _sharedInstance = [[BaseDeDatos alloc] init];
  }
  return _sharedInstance;
}

- (id)init {
  if ((self = [super init])) {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"ABC"
                                                         ofType:@"sqlite"];
    
    if (sqlite3_open([path UTF8String], &_database) != SQLITE_OK) {
      NSLog(@"¡Error al abrir la base de datos!");
    }
  }
  
  return self;
}

-(NSArray*)performQuery:(NSString*)query {
  NSMutableArray *values = [NSMutableArray array];
  
  sqlite3_stmt *statement;
  if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil)
      == SQLITE_OK) {
    while (sqlite3_step(statement) == SQLITE_ROW) {
      
      char *name = (char *) sqlite3_column_text(statement, 0);
      int value = (int) sqlite3_column_int(statement, 1);
      int mode = (int) sqlite3_column_int(statement, 2);
      
      Puntuacion *puntuacion = [[Puntuacion alloc] init];
      puntuacion.name = [NSString stringWithUTF8String:name];
      puntuacion.value = @(value);
      puntuacion.mode = @(mode);
      
      [values addObject:puntuacion];
    }
    
    sqlite3_finalize(statement);
  }
  
  return values;
}

-(NSArray*)puntuacionesOrdenadasAscendentemente {
  return [self performQuery:@"select * from puntuaciones order by puntuacion asc"];
}

-(NSArray*)puntuacionesOrdenadasPorNombre  {
  return [self performQuery:@"select * from puntuaciones order by nombre asc"];
}

-(NSArray*)puntuacionesOrdenadasPorModo {
  return [self performQuery:@"select * from puntuaciones order by modo asc"];
}

@end

Vista

Vamos al Storyboard y añadimos un UITableView y tres botones a nuestra vista. La App va a ser muy sencilla, va a mostrar los datos en la tabla y los botones van a servir para ordenarlos según un campo tal y como definimos en la base de datos.





Añadimos el siguiente código a ViewController.h:

#import 

@interface ViewController : UIViewController<UITableViewDataSource>
@property IBOutlet UITableView *tableView;

- (IBAction)orderByName:(id)sender;
- (IBAction)orderByMode:(id)sender;
- (IBAction)orderByScore:(id)sender;

@end



Volvemos a nuestro Storyboard y conectamos los botones con las acciones y la referencia del "tableView" y el datasource:



Controlador

Y por último en el "ViewController.m":

#import "ViewController.h"

#import "BaseDeDatos.h"
#import "Puntuacion.h"

@interface ViewController ()

@property NSArray *puntuaciones;

@end

@implementation ViewController

- (void)viewDidLoad
{
  [super viewDidLoad];
  self.puntuaciones = [[BaseDeDatos sharedInstance] puntuacionesOrdenadasAscendentemente];
  [self.tableView reloadData];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  if (self.puntuaciones != nil) {
    return self.puntuaciones.count;
  }
  
  return 0;
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  Puntuacion *puntuacion = self.puntuaciones[indexPath.row];
  UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"puntuacion"];
  
  cell.textLabel.text = puntuacion.name;
  cell.detailTextLabel.text = [NSString stringWithFormat:@"%@:%@", puntuacion.mode, puntuacion.value];
  
  return cell;
}

- (IBAction)orderByName:(id)sender {
  self.puntuaciones = [[BaseDeDatos sharedInstance] puntuacionesOrdenadasPorNombre];
  [self.tableView reloadData];
}

- (IBAction)orderByMode:(id)sender {
  self.puntuaciones = [[BaseDeDatos sharedInstance] puntuacionesOrdenadasPorModo];
  [self.tableView reloadData];
}

- (IBAction)orderByScore:(id)sender {
  self.puntuaciones = [[BaseDeDatos sharedInstance] puntuacionesOrdenadasAscendentemente];
  [self.tableView reloadData];
}

@end

Resultado 

Y el resultado totalmente funcional (cambia el orden al pulsar en cada botón según el criterio):


Esto evidentemente no es una App, es un punto de partida con algunos de los conceptos básicos de SQLite en iOS. Y ahora, ¡a programar!