DevTutorial #20 – Come implementare un database SQL
| 25-09-2009
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”
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”:
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”:
Abbiamo così terminato la definizione della struttura principale del nostro progetto. Se avete eseguito tutto in maniera corretta dovreste avere un progetto come questo:
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.
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:
e inseriamo “persone” come nome per il file:
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”:
Si aprirà una nuova schermata, in cui dovrete definire gli attributi della tabella. Ecco cosa dovete inserire:
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');
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”:
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:
e nella schermata che apparirà inserite la spunta a “Copy items into destination group’s folder” e cliccate su “Add”
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.
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


















Io consiglio vivamente di utilizzare coredata al posto di sqlite.
Non vedo l’ora di avere tempo per iniziare a studiare la programmazione su iPhone.
Grazie Andrea!
@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!!
[...] DevTutorial #20 – Come implementare un database SQL venerdì 25 settembre 2009 | Tratto da: http://www.bubidevs.net/ Nessun commento [...]
Grande tutorial!
Ottimo tutorial!!!
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.
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 …
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.
@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!
I tuoi tutorial sono sempre molto belli. Grazie. Ciao
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
@Rynox: grazie mille, ho appena corretto questa guida, poi correggo anche il libro
@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!
@rideMax: azz, questa non è una bella cosa..
strano.. appena riesco provo un po’ anche io, poi ti faccio sapere!
@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.
@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
@Andrea Busi:
ok grazie, ma non ho ben capito cosa intendi.
In che senso rimanere nell’iphone Simulator? Senza ricompilare?
Grazie cmq!
@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à
ok, ora non posso riprovare. Lunedi ti faccio sapere. Ciao e grazie!
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
@andrea: non ho mai provato, ma penso proprio di si.. dovrebbe funzionare correttamente..
ok, provo e poi ti dico…. cmq, ora ho risolto, ma penso sarebbe utile aver fatto un metodo per inserire elementi… grazie mille comunque…
@andrea: si, è uno dei tutorial nella “To-Do list”, speriamo di poterlo fare quanto prima
ok, se ti serve io ho risolto con una semplice funzione…
@andrea: certamente, se vuoi mandamela pure a bubidevs@gmail.com
@andrea:
sarei interessato anch’io a sapere come hai collegato un db online
raffyx@gmail.com
grazie mille
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..
@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..
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…
@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
e cosi ora mi tocca impararmi anche il php…. casomai potresti fare un tutorial sulle 4 cose di php k servono
;)
@andrea: purtroppo di php so davvero troppo poco, so solo modificare un po’ le pagine già fatte, ma non so scriverle da zero xD