No desenvolvimento iOS, o SQLite3 é uma opção leve e eficiente para armazenamento local de dados. Para utilizá-lo, é necessário vincular a biblioteca libsqlite3.tbd (ou .dylib em versões antigas) ao projeto e incluir o cabeçalho principal <sqlite3.h>, que expõe uma API em C pura.
Ao criar um novo projeto com quatro botões — inserir, excluir, atualizar e consultar —, podemos demonstrar operações básicas com o banco de dados.
Abrindo o Banco de Dados
A função sqlite3_open() recebe o caminho do arquivo do banco de dados (como string C) e um ponteiro duplo para um objeto sqlite3*. Se o arquivo não existir, ele será criado automaticamente. O retorno é um inteiro: SQLITE_OK indica sucesso.
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *dbPath = [documentsPath stringByAppendingPathComponent:@"students.sqlite"];
const char *cPath = [dbPath UTF8String];
sqlite3 *database;
int openResult = sqlite3_open(cPath, &database);
if (openResult == SQLITE_OK) {
NSLog(@"Banco de dados aberto com sucesso");
} else {
NSLog(@"Falha ao abrir o banco: %d", openResult);
}
Criando uma Tabela
Usamos sqlite3_exec() para executar comandos DDL, como a criação de tabelas. A instrução SQL é passada como string C, e um ponteiro para mensagem de erro permite diagnóstico detalhado.
const char *createTableSQL = "CREATE TABLE IF NOT EXISTS alunos ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"nome TEXT NOT NULL, "
"idade INTEGER NOT NULL);";
char *errorMsg = NULL;
int execResult = sqlite3_exec(database, createTableSQL, NULL, NULL, &errorMsg);
if (execResult != SQLITE_OK) {
fprintf(stderr, "Erro na criação da tabela: %s (linha %d)\n", errorMsg, __LINE__);
sqlite3_free(errorMsg);
}
Inserindo Registros
Para inserir dados, montamos dinamicamente uma instrução SQL e a executamos via sqlite3_exec(). É essencial validar o resultado e liberar mensagens de erro quando necessário.
- (void)inserirRegistros {
for (int i = 0; i < 15; i++) {
NSString *nomeAluno = [NSString stringWithFormat:@"Aluno_%u", arc4random_uniform(1000)];
int idade = 15 + arc4random_uniform(16); // Idade entre 15 e 30
NSString *insertSQL = [NSString stringWithFormat:
@"INSERT INTO alunos (nome, idade) VALUES ('%@', %d);", nomeAluno, idade];
char *err = NULL;
int res = sqlite3_exec(database, [insertSQL UTF8String], NULL, NULL, &err);
if (res != SQLITE_OK) {
NSLog(@"Erro na inserção: %s", err);
sqlite3_free(err);
}
}
}
Consultando Dados
Para consultas (SELECT), recomenda-se usar a interface preparada: sqlite3_prepare_v2(), sqlite3_step() e sqlite3_column_*. Isso evita injeção SQL e oferece melhor desemepnho em repetições.
- (void)consultarJovens {
const char *query = "SELECT id, nome, idade FROM alunos WHERE idade < 20;";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, query, -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
int identificador = sqlite3_column_int(statement, 0);
const unsigned char *nome = sqlite3_column_text(statement, 1);
int anos = sqlite3_column_int(statement, 2);
printf("ID: %d | Nome: %s | Idade: %d\n", identificador, nome, anos);
}
sqlite3_finalize(statement);
} else {
NSLog(@"Falha ao preparar consulta");
}
}
O arquivo do banco de dados é armazenado no diretório de documentos do aplicativo (sandbox), podendo ser inspecionado durante o desenvolvimento usando o Finder ou ferramentas como DB Browser for SQLite.