Olá povo,
Eu já mostrei aqui no blog como
persistir informações no iOS utilizando o SQLite. Para quem quer ter um controle maior sobre o que está sendo salvo no banco de dados, é uma boa opção. Entretanto a Core Data realiza o mapeamento objeto-relacional de uma forma bem interessante e nos poupa de escrever um monte de código de baixo nível (uma vez que a lib do SQLite é escrita em C).
Crie um novo projeto no Xcode do tipo
Single View Application e mãos à obra! Se você selecionar o template
Master/Detail application no assistente, aparecerá a opção para utilizar Core Data. Isso servirá para incluir a lib do Core Data no projeto e inserir algum código para nós. Se não usar esse template, teremos que adicionar manualmente. Para isso, basta selecionar o projeto, e na aba
Build Fases na seção
Link Binary With Libraries e clicar em "+". Na lista que será exibida, selecione
CoreData.framework.
Vamos agora adicionar ao projeto o arquivo onde ficarão as definições das entidades que serão persistidas no banco. No Xcode, selecione
File | New | File... selecione a opção
Core Data no lado esquerdo, e então selecione a opção
Data Model. Clique em
Next e nomeie o arquivo para CarroModel, em seguida, clique em
Create para concluir o assistente.
Selecione o arquivo recém criado, e clique no botão
Add Entity que fica na parte inferior. Renomeie a entidade para Carro. Em seguida, clique no botão
Add Attribute, selecione o atributo e o renomeie para "nome" e modifique seu tipo (na janela da direita) para String (através da propriedade
Attribute Type). Adicione mais dois atributos, placa e ano, e modifique os seus tipos para String e Int16 respectivamente.
Abaixo a imagem do model após nossas alterações.
Vamos agora criar a classe carro que será persistida no banco de dados. Selecione a entidade Carro e clique no menu
File | New | File... Na janela que for exibida, selecione
Core Data no lado esquerdo, e então selecione
NSManagedObject subclass. Será criada a classe Carro conforme abaixo.
// Carro.h -----------------------------
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface Carro : NSManagedObject
@property (nonatomic, retain) NSString * nome;
@property (nonatomic, retain) NSString * placa;
@property (nonatomic, retain) NSNumber * ano;
@end
// Carro.m -----------------------------
#import "Carro.h"
@implementation Carro
@dynamic nome;
@dynamic placa;
@dynamic ano;
@end
Notem que nossa classe herda de
NSManagedObject o que quer dizer que os objetos dessa classe serão persistidos. Outro detalhe é que os atributos são implementados com
@dynamic.
Crie uma nova classe chamada RepositorioCarro e deixe-a conforme abaixo.
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Carro;
@interface RepositorioCarro : NSObject {
NSManagedObjectModel *mom;
NSPersistentStoreCoordinator *coordinator;
NSManagedObjectContext *context;
}
- (void) test;
- (Carro *) newCarro;
- (void) salvar;
- (void) excluir:(Carro *)carro;
- (NSArray *) todosCarros;
@end
Nessa classe, declaramos um NSManagedObjectModel, NSPersistentStoreCoordinator e um NSManagedObjectContext. Vamos entender o papel de cada um:
-
NSManagedObjectContext é a classe que vai realizar as operações com o banco. Logo, para inserir, alterar, excluir ou obter objetos (
NSManagedObject) do banco, utilizamos métodos dessa classe.
-
NSPersistentStoreCoordinator é como se fosse a conexão com o banco. É nela onde você define o local onde está armazenado o arquivo do banco e outras configurações adicionais.
-
NSManagedObjectModel é o esquema do banco de dados. Que aqui no nosso projeto é o arquivo onde definimos o modelo da classe Carro.
O código abaixo inicia com o "construtor" da classe, que chama o método initContext. Esse método por sua vez chama o initCoordinator que por sua vez chama o initMom.
#import "RepositorioCarro.h"
#import "Carro.h"
@implementation RepositorioCarro
- (id) init {
self = [super init];
[self initContext];
return self;
}
// Retorna a URL para o diretório Documents
- (NSURL *)appDocsDir {
return [[[NSFileManager defaultManager]
URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
}
// Carrega o arquivo de modelo
- (void) initMom {
NSURL *modelURL = [[NSBundle mainBundle]
URLForResource:@"CarroModel"
withExtension:@"momd"];
mom = [[NSManagedObjectModel alloc]
initWithContentsOfURL:modelURL];
}
// Abre a conexão com o banco
- (void) initCoordinator {
[self initMom];
NSURL *storeURL = [[self appDocsDir]
URLByAppendingPathComponent:
@"CarrosDB.sqlite"];
NSError *error = nil;
coordinator =
[[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:mom];
if (![coordinator
addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeURL
options:nil error:&error]) {
NSLog(@"Erro... %@",
[error localizedDescription]);
}
}
// Inicializa o contexto
- (void) initContext {
[self initCoordinator];
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:coordinator];
}
- (void) test {
// Testando inserção
Carro *carro = [self newCarro];
carro.nome = @"Uno";
carro.placa = @"UNO0001";
carro.ano = [NSNumber numberWithInt:2000];
[self commit];
// Testando alteração
carro = @"Palio";
[self commit];
// Testando listagem...
NSArray *fetchedObjects = [self todosCarros];
for (Carro *carro in fetchedObjects) {
NSLog(@"Nome: %@", carro.nome);
NSLog(@"placa: %@", carro.placa);
}
}
// A classe carro não deve ter construtor e
// deve ser inicializada dessa forma.
- (Carro *) newCarro {
return [NSEntityDescription
insertNewObjectForEntityForName:@"Carro"
inManagedObjectContext:context];
}
// As alterações que são feitas nos objetos
// são persistidas no banco ao dar commit
- (void) commit {
NSError *error;
if (![context save:&error]) {
NSLog(@"Erro... %@",
[error localizedDescription]);
}
}
- (void) excluir:(Carro *)carro {
[context deleteObject:carro];
}
- (NSArray *) todosCarros {
NSFetchRequest *fetchRequest =
[[NSFetchRequest alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"Carro"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error;
return [context
executeFetchRequest:fetchRequest
error:&error];
}
@end
O método newCarro cria uma nova instância de um objeto carro no contexto. Ou seja, se comitarmos esse objeto ele já estará persistido no banco. Se alterarmos uma propriedade de um objeto carro do array que é retornado pelo método todosCarros, e depois chamarmos o método commit, a alteração já é realizada no banco de dados.
O método test, como próprio nome diz, serve para testarmos nossa classe. Onde inserimos, alteramos e listamos as informações do banco.
Qualquer dúvida, deixem seus comentários.
4br4ç05,
nglauber
Fonte: http://www.raywenderlich.com/934/core-data-on-ios-5-tutorial-getting-started