Abbonati al feed RSS!
twitter
  •  

DevTutorial #20 – Come implementare un database SQL

|
Categorie: DevTutorial

33

Eccoci con un nuovo tutorial dedicato alla programmazione per iPhone SDK. Oggi vedremo come implementare un database SQL all’interno delle nostre applicazioni. Creeremo una tabella in cui andremo ad inserire i valori letti dal nostro database, dopo aver eseguito una query predefinita.

Devo premettere, però, che non parlerò di SQL e database relazionali, che devono essere già conosciuti da chi affronta questo tutorial. È una scelta che potrebbe non piacere a molti di voi, però richiederebbe troppo tempo e una trattazione che non può essere fatta in un semplice tutorial. Detto ciò, è possibile seguire il tutorial anche senza conoscere niente di SQL, ovviamente alcune caratteristiche e alcuni passaggi potrebbero risultare di difficile comprensione.

In questo tutorial sentirete spesso parlare di SQLite, ma cosa è di preciso?

SQLite è una libreria che implementa un DBMS SQL, permettendo di creare un database all’interno di un unico file. Esso è molto indicato per scopi come il nostro, ovvero la creazione di applicazioni per dispositivi mobili, che non possono permettersi di avere un DMBS dedicato per la gestione delle basi di dati.
Ovviamente fornisce un supporto parziale all’SQL, in quanto manca di alcune caratteristiche avanzate, che però dubito possiate utilizzare all’interno di un’applicazione. SQLite, comunque, è molto veloce e leggero, perfetto quindi per applicazioni per iPhone.

1) Creiamo un nuovo progetto e la struttura necessaria

Iniziamo creando un nuovo progetto di tipo “Navigation-based Application” e chiamiamolo “sqlTutorial”

Immagine 1

Abbiamo quindi creato un progetto che ci fornisce già l’implementazione di una tabella, che visualizzerà i dati letti dal nostro database.

Dobbiamo, però, inserire altre due cose molto importanti: una classe che si occuperà di comunicare con il database, e la libreria che permette tale comunicazione.

Iniziamo creando la classe che serirà ai nostri scopi. Andiamo in “File -> New File…” e creiamo una “Objective-C class”, chiamandola semplicemente “Data”:

Immagine 2

Dobbiamo ora inserire nel nostro progetto la libreria (o framework) che si occupa del collegamento con il database sql. Clicchiamo con il tasto destro sulla cartella “Frameworks” all’interno del nostro progetto, poi andiamo in “Add -> Existing Frameworks…” e dall’elenco seguente che apparirà selezioniamo “libsqlite3.0.dylib”:

Immagine 3

Abbiamo così terminato la definizione della struttura principale del nostro progetto. Se avete eseguito tutto in maniera corretta dovreste avere un progetto come questo:

Immagine 4

2) Definiamo la classe “Data”

Dobbiamo ora implementare la classe “Data”, su cui si basa gran parte di questo tutorial. Prima di iniziare a scrivere codice, focalizziamo l’attenzione su ciò che deve fare questa classe. Essa avrà il compito di:

  • creare una connessione con il database (di cui noi specificheremo un indirizzo, in questo caso locale, ma nulla vieterebbe di avere un database in remoto);
  • interrogare la base di dati eseguendo una query impostata via codice;
  • inserire i risultati della query all’interno di un’array, che verrà poi visualizzato all’interno della tabella;

Vediamo ora di implementare queste funzionalità, più altre caratteristiche che ci serviranno come supporto.

Iniziamo aprendo il file “Data.h” e inserendo il seguente codice:

#import <Foundation/Foundation.h>
#import <sqlite3.h>
 
@interface Data : NSObject {
   // Lista contenente i dati letti dal database
   NSMutableArray *lista;
}
 
- (id)init:(NSString *)pathDB;
- (void)caricaValoriDaDB:(NSString *)dbPath;
- (unsigned)getSize;
- (id)objectAtIndex:(unsigned)theIndex;
 
@property (nonatomic, retain) NSMutableArray *lista;
 
@end

Alla riga numero 6 abbiamo dichiarato un array (di tipo NSMutableArray, quindi modificabile anche dopo la sua inizializzazione), che conterrà i valori letti dal database.  Dalla riga 9 alla 12 abbiamo definito i metodi che ci serviranno in tale classe, che implementeremo fra poco. Da notare, inoltre, la classe importata alla riga 2: è necessaria per dire alla nostra classe di utilizzare la libreria che abbiamo importato all’inizio della guida.

Apriamo ora il file “Data.m” e iniziamo ad inserire il seguente codice:

#import "Data.h"
 
static sqlite3 *database = nil;
 
@implementation Data
 
@synthesize lista;
 
// Inizializziamo l'oggetto della classe Data
- (id)init:(NSString *)pathDB{
    // carichiamo i valori dal database
    [self caricaValoriDaDB:pathDB];
    return self;
}
 
// Ritorna la dimensione della lista (n° di elementi letti dal db)
- (unsigned)getSize {
    return [lista count];
}
 
// Ritorna l'oggetto ad una data posizione
- (id)objectAtIndex:(unsigned)index {
    return [lista objectAtIndex:index];
}

La prima istruzione particolare compare alla riga 3, ed è la definizione dell’oggetto che ci servirà per creare la connessione con il database.
Alla riga 10 viene dichiarato il primo metodo, “init”, che deve essere invocato quando si vuole inizializzare un oggetto appartenente alla classe Data. Alla riga 12 viene chiamiamo il metodo “caricaValoriDaDB”, che ha il compito di interfacciarsi con il database ed eseguire le query sui dati (vedremo fra poco la sua implementazione). Il “return self” alla riga 13, infine, ritorna il puntatore dell”oggetto appena creato.

Alla riga 17 definiamo “getSize”, un semplice metodo che ci ritorna la dimensione della lista, e quindi il numero di elementi letti dalla nostra query. Questo ci servirà quando andremo a definire la tabella.

Infine, alla riga 22, definiamo un metodo che ci ritorna un oggetto presente ad una determinata posizione della nostra lista. Ad esempio, potremo recuperare il 5° elemento della nostra lista, per poi elaborarlo oppure mostrarlo all’utente.

Dobbiamo ora implementare il metodo più complesso di questa classe, ovvero “caricaValoriDaDB”. Ecco il codice di tale metodo:

// Carica i valori dal database passato come parametro
-(void)caricaValoriDaDB:(NSString *)dbPath {
        // lista temporanea
	NSMutableArray *listaTemp = [[NSMutableArray alloc] init];
	// Oggetto che contiene i vari elementi
        NSMutableDictionary *dictionary;
 
	NSMutableString *idPersona;//id della persona
	NSMutableString *nome;//nome della persona
	NSMutableString *cognome;//cognome della persona
 
	if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
		// query che ricava i valori
		const char *sql = "select ID, Nome, Cognome from PERSONA";
		sqlite3_stmt *selectstmt;
 
		if(sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK) {
 
			while(sqlite3_step(selectstmt) == SQLITE_ROW) {
				// ricaviamo i valori letti dalla query
				idPersona = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 0)];
				nome = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
				cognome = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 2)];
				// inseriamo tutti i valori letti in un unico oggetto
				dictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:idPersona, @"id", nome, @"nome", cognome, @"cognome", nil];
 
				[listaTemp addObject:dictionary];
				[dictionary release];
			}
		}
		self.lista = listaTemp;
		[listaTemp release];
	}
	else
		sqlite3_close(database);
}

Iniziamo ad analizzare questo metodo. Partiamo dall’intestazione, in cui viene definito un parametro “dbPath”: questo è il percorso del nostro database. Esso lo definiremo in seguito, nella classe che gestisce la tabella. In questo tutorial il database sarà in locale, ovverò sarà fisicamente presente nella cartella del nostro progetto. Nulla vieta, comunque, di inserire un indirizzo remoto, che ci consenta di connetterci ad un database presente su un server.

Subito dopo, creiamo alcuni oggetti, che ci servono per gestire i dati ricavati dalle query. Abbiamo, infatti, un oggetto “dictionary”, che conterrà i vari elementi ricavati dall’interrogazione al database. Le stringhe “idPersona”, “nome”, “cognome”, infatti, servono per salvare i valori letti, e inserirli all’interno dell’oggetto appena menzionato.

Alla riga 37 viene aperta la connessione con il database: essa si trova all’interno di un ciclo “if”: se tale controllo da esito positivo, si possono elaborare i dati, altrimenti si passa alla fine del metodo, in quanto non è possibile instaurare una connessione con il database. Se la connessione è stata creata, possiamo creare la query che andremo poi ad eseguire (riga 39). Alla riga 42 eseguiamo poi tale query: anche in questo caso, se l’esecuzione ha avuto successo, possiamo ricavare i valori desiderati, altrimenti non verrà eseguita nessuna operazione.

Il ciclo while (riga 44) ci permetterà di scorrere tutti i risultati della nostra query (che potrebbero essere, ovviamente, più di uno), fino al termine. Potete notare che i risultati vengono inseriti in un oggetto di tipo “NSMutableDictionary”: esso è come un grande contenitore, che ci permette di inserire valori associandoci un tag (quello che facciamo alla riga 50).

Come vedete non si tratta di operazioni complesse, si tratta solo di capire come funziona il meccanismo, che potete poi variare a seconda delle vostre esigenze.

Gli ultimi due metodi da inserire nel file “Data.m” sono i seguenti:

+(void)finalizeStatements {
	if(database)
		sqlite3_close(database);
}
 
-(void)dealloc {
	[lista release];
	[super dealloc];
}

Il primo si occupa di concludere la query e di chiudere la connessione al database (va sempre messo), mentre il secondo è il classico “dealloc”.

Abbiamo concluso con la definizione della classe “Data”. Ora vedremo come creare il nostro database e inserirlo nel progetto.

3) Creiamo il database

Quello che dobbiamo andare a realizzare è un semplice database, con tecnologia sqlite. Per crearlo utilizzeremo un plug-in per Firefox, chiamato” SQLite Manager”, che potete trovare a questo indirizzo. In alternativa esistono alcuni programmi dedicati, come SQLiteManager, che è, però, a pagamento.

Immagine 5

Dopo aver installato l’estensione, andiamo in “Strumenti -> SQLite Manager”, si avvierà il tool che ci permetterà di creare il nostro database. Clicchiamo sull’icona del foglio bianco per crare un nuovo database:

Immagine 6

e inseriamo “persone” come nome per il file:

Immagine 7

e scegliamo dove salvare il file (vi consiglio sulla Scrivania, così potrete recuperarlo subito in seguito).

Abbiamo così creato il nostro database, che risulta però essere completamente vuoto. Dobbiamo, quindi, creare la tabella “Persone”. Per fare ciò, facciamo clic con il tasto destro su “Tables” che trovate nella parte sinistra della schermata, e selezioniamo “Create Table”:

Immagine 8

Si aprirà una nuova schermata, in cui dovrete definire gli attributi della tabella. Ecco cosa dovete inserire:

Immagine 9

e clicchiamo poi su “Yes” nel messaggio successivo che apparirà.

Abbiamo inserito gli attributi necessari, ovvero nome, cognome e un identificativo univoco (id).
Non ci resta che inserire dei valori nella tabella. Per fare ciò, andate nella sezione “Execute SQL” inserite le seguenti istruzioni:

INSERT INTO PERSONA (id,Nome,Cognome) VALUES ('1','Giovanni','Verdi');
INSERT INTO PERSONA (id,Nome,Cognome) VALUES ('2','Paolo','Rossi');
INSERT INTO PERSONA (id,Nome,Cognome) VALUES ('3','Luca','Bianchi');
INSERT INTO PERSONA (id,Nome,Cognome) VALUES ('4','Andrea','Busi');

Immagine 10

Un messaggio in “Last Error” vi comunicherà se vi sono stati errori nell’inserimento dei dati, oppure se tutto è andato per il verso giusto.

Possiamo, infine, controllare i valori che abbiamo inserito, spostandoci nella sezione “Browse & Search”:

Immagine 11

Abbiamo concluso! Chiudiamo pure il programmino, i cambiamenti sono già stati apportati al nostro database.

4) Concludiamo l’applicazione

Torniamo ora ad XCode, e concludiamo lo sviluppo della nostra applicazione. Per prima cosa, dobbiamo inserire il database che abbiamo creato nel nostro progetto. Trasciniamo il file all’interno di XCode:

Immagine 12

e nella schermata che apparirà inserite la spunta a “Copy items into destination group’s folder” e cliccate su “Add”

Immagine 13

Siamo pronti per completare la nostra applicazione. Iniziamo aprendo il file “RootViewController.h” e inseriamo il seguente codice:

#import "Data.h"
 
@interface RootViewController : UITableViewController {
 // Oggetto con la lista degli elementi letti dal db
 Data *dataList;
}
 
@end

Alla riga 5 abbiamo dichiarato la lista che conterrà gli elementi letti dal database. Per capirci, è quella che viene creata dal metodo “caricaValoriDaDB”, che abbiamo definito in precedenza.

Passiamo ora al file “RootViewController.m”. Iniziamo con il metodo “viewDidLoad”, che, come ormai dovreste sapere, ci consente di eseguire delle operazioni al caricamento dell’applicazione. Ecco come dovete modificare tale metodo:

- (void)viewDidLoad {
    [super viewDidLoad];
 
	self.title = @"Lista Autori";
	//leggiamo il path del database
	NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"persone.sqlite"];
 
	//creiamo la lista degli autori
	dataList = [[Data alloc] init:defaultDBPath];
}

Alla riga 4 impostiamo il titolo alla nostra tabella, mentre alla riga 6 definiamo il percorso del nostro database. A prima vista può sembrare complessa, ma essa non fa altro che rilevare il percorso in cui si trova l’applicazione (sia essa su iPhone Simulator che su iPhone fisico) e aggiungere a tale percorso “persone.sqlite”, che è proprio il database che abbiamo inserito nel nostro progetto.
Alla riga 9, infine, inizializziamo la lista, passando alla funzione “init” proprio il percorso che abbiamo definito poche righe sopra.

Dobbiamo, ora, definire i metodi necessari per settare la tabella. Abbiamo già visto questi metodi nei tutorial dedicati alle tableView, quindi non mi soffermerò troppo sulla spiegazione. Sempre all’interno del file “RootViewController.m”, scorretelo verso il fondo, e troverete i metodi del protocollo UITableView, che dovrete completare nel seguente modo:

#pragma mark Table view methods
 
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
 
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [dataList getSize];
}
 
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 
    static NSString *CellIdentifier = @"Cell";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
 
	NSDictionary *itemAtIndex = (NSDictionary *)[dataList objectAtIndex:indexPath.row];
	cell.textLabel.text = [itemAtIndex objectForKey:@"nome"];
 
    return cell;
}

I tre metodi sono i soliti che vanno inseriti quando si lavora con le UITableView. Concentriamoci un attimo sulle righe 22 e 23. Esse hanno il compito di ricavare un oggetto dalla lista “dataLista” (che contiene tutti i valori letti da database), per estrarne poi il nome desiderato (ovviamente vengono estratti tutti i nomi, dal primo all’ultimo). Potete vedere che dall’oggetto “itemAtIndex” viene estratto solo il nome: potremmo creare anche altre combinazioni, ad esempio con il cognome. Per fare ciò vi basterà modificare la riga 23 ad esempio nel seguente modo:

[itemAtIndex objectForKey:@"cognome"];

Abbiamo concluso la nostra applicazione! Clicchiamo su “Build and Go!” e controlliamo che funzioni tutto in maniera corretta.

Immagine 14

Se Avete Problemi, questo è il nostro file di progetto.

La guida è stata creata da Andrea Busi per “Bubi Devs”. I meriti, quindi, sono del legittimo autore.

1.654 visite

Commenti (33)

Reply to this comment

Io consiglio vivamente di utilizzare coredata al posto di sqlite.

Reply to this comment

Non vedo l’ora di avere tempo per iniziare a studiare la programmazione su iPhone.
Grazie Andrea!

Reply to this comment

@Dzamir: hai ragione, però SQL rimane la tecnologia più usata, quindi un tutorial mi sembrava d’obbligo..
Comunque spero di poter fare un tutorial anche su CoreData in futuro! ;-)

@Ducadicrespo: ihih, comincia il prima possibile, mai perdere la voglia!!

Reply to this comment

[...] DevTutorial #20 – Come implementare un database SQL venerdì 25 settembre 2009 | Tratto da: http://www.bubidevs.net/ Nessun commento [...]

Reply to this comment

Grande tutorial!

Reply to this comment

Ottimo tutorial!!! :P :P :P

Reply to this comment

Infatti se si hanno forte conoscenze di sqlite o un database già impostato conviene seguire questa strada. Ma per i nuovi arrivati che non sanno che tecnologia scegliere consiglio coredata che, se utilizzato opportunamente, è ordini di magnitudo superiore alle semplici query sql.

Reply to this comment

Vorrei segnalare che esiste anche un altro software free che permette di creare/editare/analizzare i file SQLite.
http://sqlitebrowser.sourceforge.net/

PS: chiaramente, per i nostalgici della shell, si può fare anche dal terminal … ma non è molto user friendly …

Reply to this comment

Andrea innanzitutto complimenti per questo tutorial che era quello che stavo aspettando per la mia nuova applicazione.
Ho iniziato solo da qualche mese a sviluppare per iphone, fino ad ora ho sempre usato RPG, Visual Basic e l’approccio all’objective-C diciamo che non è stato proprio indolore.
Ma piano piano sto iniziando a venir fuori dal fango grazie anche a tutorial come questo.
Questo sito è tra i miei preferiti e lo consulto ogni giorno, appena mi siedo davanti al mio mac.
Continua così
D.

Reply to this comment

@DaveDevil: grazie mille! queste sono le cose che mi rendono fiero del mio piccolo sito, sapere che per qualcuno sono un punto di riferimento..
grazie ancora e continua a seguirci! ;-)

Reply to this comment

I tuoi tutorial sono sempre molto belli. Grazie. Ciao

Reply to this comment

Credo ci sia un errore nell’ultima riga di codice che proponi, ovvero nel caso in cui volessimo estrapolare anche il cognome (linea 23):

[itemAtIndex objectForKey:@"nome"]

Stessa errore anche nella tua guida in vendita, unica differenza è che li hai aggiunto il “;” a fine istruzione ;)

Reply to this comment

@Rynox: grazie mille, ho appena corretto questa guida, poi correggo anche il libro ;-)

Reply to this comment

@Andrea Busi:
ciao, provando a lanciare anche una insert mi accorgo che, una volta rialnciata l’applicazione il database mi si presenta vuoto, anche se lo statement (insert) è stato correttamente eseguito.
Come mai il database non è persistente?

Ottimo tutorial, comunque!

Reply to this comment

@rideMax: azz, questa non è una bella cosa..

strano.. appena riesco provo un po’ anche io, poi ti faccio sapere!

Reply to this comment

@Andrea Busi:
ho seguito il tuo tutorial che è ottimo, aggiunto una procedura di insert. Dopo la procedura e anche dopo la chiusura dell’applicazione il database è corretto e contiene gli elementi giusti (il database viene copiato nella cartella myApp.app giusto?),

Appena rilancio l’applicazione il database ridiventa vuoto. Credo sia un problema dovuto alla gestione del file system locale dell’iphone (come funziona esattamente?) e non sono riuscito a risolvere.
Ciao e grazie.

Reply to this comment

@rideMax: ma certo, elementare Watson!!

quando ricompili l’applicazione, viene creato nuovo anche il database, quindi le modifiche che hai apportato vanno perse..

prova a modificare il database, uscire dal tuo programma ma rimanere in iPhone Simulator, vedrai che quando la riapri le modifiche ci saranno ;-)

Reply to this comment

@Andrea Busi:
ok grazie, ma non ho ben capito cosa intendi.
In che senso rimanere nell’iphone Simulator? Senza ricompilare?
Grazie cmq!

Reply to this comment

@rideMax: si esatto.. ogni volta che ricompili l’applicazione viene inserito il database originale, quello che hai inserito nel progetto..

Se tu non chiudi l’iPhone Simulatore, e riapri l’applicazione (senza ricompilarla quindi) vedrai che funzionerà ;-)

Reply to this comment

ok, ora non posso riprovare. Lunedi ti faccio sapere. Ciao e grazie!

Reply to this comment

ciao, volevo chiederti una cosa, posso utilizzare questo metodo anche per connettermi ad un db on-line?? mi dovrei connettere al mio sito per fare delle query sul database e poi cambiare dei valori

Reply to this comment

@andrea: non ho mai provato, ma penso proprio di si.. dovrebbe funzionare correttamente..

Reply to this comment

ok, provo e poi ti dico…. cmq, ora ho risolto, ma penso sarebbe utile aver fatto un metodo per inserire elementi… grazie mille comunque…

Reply to this comment

@andrea: si, è uno dei tutorial nella “To-Do list”, speriamo di poterlo fare quanto prima ;-)

Reply to this comment

ok, se ti serve io ho risolto con una semplice funzione…

Reply to this comment

@andrea: certamente, se vuoi mandamela pure a bubidevs@gmail.com

Reply to this comment

@andrea:

sarei interessato anch’io a sapere come hai collegato un db online

raffyx@gmail.com

grazie mille

Reply to this comment

Ciao Andrea…. son ancora alle prese con la connessione al database on-line, ho fatto diverse prove ma non ci riesco…. mi diresti se c’è un modo spicciolo per farlo??
grazie..

Reply to this comment

@andrea: ciao, ho provato a cercare su Internet, perchè serviva anche a me ma non ho trovato niente ;-(

proverò a cercare ancora, se trovo qualcosa ti farò sapere e sicuramente aggiornerò la guida..

Reply to this comment

cercando in rete non ho trovato niente… ho letto però che consigliano di usare il php se si deve lavorare su db on-line…. e poi creare il proprio db in locale ( bisogna vedere la mole di dati) solo che il problema è k di php non ne so niente…
mi sa che dovrò imparare il php….:)
secondo me ti conviene utilizzare il php, alla fine mi sembra anche piu facile da utilizzare…

Reply to this comment

@andrea: esatto, ho trovato anche io così.. a dire la verità ci sono rimasto un po’ male, non vedo perchè debba passare attraverso una pagina in php per accedere al mio db..

va beh, proveremo anche questa soluzione dai ;-)

Reply to this comment

e cosi ora mi tocca impararmi anche il php…. casomai potresti fare un tutorial sulle 4 cose di php k servono ;) ;)

Reply to this comment

@andrea: purtroppo di php so davvero troppo poco, so solo modificare un po’ le pagine già fatte, ma non so scriverle da zero xD

Scrivi un commento!