iPhone中persist data有很多方法,比如NSUserDefaults,NSKeyedArchiver,SQLite3,Core Data等等,具体请参照深入理解iPhone数据持久化。
今天我们主要讨论Core data。Core data是存储not-trivial数据最好的一种,它可以降低内存负荷,增加可靠性,可以让你原理底层的数据库操作。
Core Data主要是对sqlite3的包装,让你能在上层自由操作sqlite3数据库。
主要概念:
要理解Core Data,主要是要理解三个主要的概念:
- Managed Object Model: You can think of this as the database schema. It is a class that contains definitions for each of the objects (also called “Entities”) that you are storing in the database. Usually, you will use the visual editor you just peeked at to set up what objects are in the database, what their attributes, and how they relate to each other. However, you can do this with code too!
- Persistent Store Coordinator: You can think of this as the database connection. Here’s where you set up the actual names and locations of what databases will be used to store the objects, and any time a managed object context needs to save something it goes through this single coordinator.
- Managed Object Context: You can think of this as a “scratch pad” for objects that come from the database. It’s also the most important of the three for us, because we’ll be working with this the most. Basically, whenever you need to get objects, insert objects, or delete objects, you call methods on the managed object context (or at least most of the time!)
Managed Object Model是数据库的schema,数据库table中具体包括什么内容,都包含在这个类中。你可以通过File->New File->Core Data->Data Model新建一个Data model,加入你设计的data item后,再通过File->New File->Core Data->NSManagedObjectSubclass可以自动建立NSManagedObject的子类。
Persistent Store Coordinator: 这是具体执行数据库操作的类,但是你一般不会直接用到这个类,一般你都是直接操作Managed Object Context类,Managed Object Context类会再调用Persistent Store Coordinator来执行操作。
Managed Object Context:是最重要的类。所有的数据操作(插入,删除,更新等)都需要直接调用该类来执行。
具体方法:
如何建立Data Model?
New File->Core Data->Data Model: 新建一个xcdatamodeld文件,你可以在这个文件中添加具体的Attributes和Types。
New File->Core Data->NSManagedObjectSubclass:新建NSManagedObject的子类,他会自动添加你刚刚设计的数据项。
设计CoreDataHelper类:
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil)
{
return _managedObjectContext;
}
if (self.persistentStoreCoordinator != nil)
{
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
}
return _managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil)
{
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:FWD_FILE_COREDATAMODEL withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil)
{
return _persistentStoreCoordinator;
}
// create a new persistent store of the appropriate type
NSError *error = nil;
NSURL *storeURL = @"The URL you want to save the .sqlite file";
storeURL = [storeURL URLByAppendingPathComponent:@"MyCoreData.sqlite"];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSDictionary *ui = [error userInfo];
for(NSString *err in [ui keyEnumerator]) {
NSLog(@"err:%@",[ui objectForKey:err]);
}
abort();
}
return _persistentStoreCoordinator;
}
如何搜索数据:
/**
* Search all records in Entity entityName with condition predicate.
*/
- (NSArray *)searchWithEntityName:(NSString *)entityName predicate:(NSPredicate *)predicate
{
NSFetchRequest *fetchReqeust = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:self.managedObjectContext];
[fetchReqeust setEntity:entity];
if (predicate != nil)
{
[fetchReqeust setPredicate:predicate];
}
NSError *error = nil;
NSArray *array = [self.managedObjectContext executeFetchRequest:fetchReqeust error:&error];
if (error != nil)
{
NSLog(@"Fetch request error, %@", [error localizedDescription]);
return nil;
}
return array;
}
这里NSPredicate主要功能是设定搜索条件,比如
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(type == %@) AND (updatedAt == %@)", type, updatedAt];
主要是查找所有type和updatedAt都符合条件的项。
NSPredicate的具体用法,请参照 Using NSPredicate to Filter Data.
如何添加数据到指定Table:
- (NSManagedObject *)addEntityWithName:(NSString *)entityName dicData:(NSDictionary *)dicData;
{
NSLog(@"dicData: %@", [dicData description]);
NSManagedObject *record = [NSEntityDescription insertNewObjectForEntityForName:entityName
inManagedObjectContext:self.managedObjectContext];
[record setValuesForKeysWithDictionary:dicData];
if (record == nil)
{
return nil;
}
NSError *error = nil;
if (![self.managedObjectContext save:&error])
{
NSLog(@"Save data to revision error 2, %@", [error localizedDescription]);
return nil;
}
return record;
}
这里entityName是Data Mode的名称,dicData是要添加的数据。
如何更新数据:
/**
* Update NSManagedObject with new data.
*/
- (BOOL)updateManagedObject:(NSManagedObject *)managedObject dicData:(NSDictionary *)dicData
{
[managedObject setValuesForKeysWithDictionary:dicData];
NSError *error = nil;
if (![managedObject.managedObjectContext save:&error])
{
NSLog(@"Save data to revision error 1, %@", [error localizedDescription]);
return NO;
}
return YES;
}
/**
* Update a NSManagedObject in the Entity with condition predicate.
*/
- (BOOL)updateWithEntityName:(NSString *)entityName predicate:(NSPredicate *)predicate dicData:(NSDictionary *)dicData
{
NSArray *managedObjects = [self searchWithEntityName:entityName predicate:predicate];
for (NSManagedObject *item in managedObjects)
{
[item setValuesForKeysWithDictionary:dicData];
}
NSError *error = nil;
if (![self.managedObjectContext save:&error])
{
NSLog(@"Save data to revision error 1, %@", [error localizedDescription]);
return NO;
}
return YES;
}
如何删除数据:
/**
* Delete a NSManagedObject.
*/
- (BOOL)deleteManagedObject:(NSManagedObject *)managedObject
{
[self.managedObjectContext deleteObject:managedObject];
NSError *error = nil;
if (![self.managedObjectContext save:&error])
{
NSLog(@"Error delete - error:%@", [error localizedDescription]);
return NO;
}
return YES;
}
/**
* Delete a NSManagedObject in the Entity with condition predicate.
*/
- (BOOL)deleteWithEntityName:(NSString *)entityName predicate:(NSPredicate *)predicate
{
NSArray *items = [self searchWithEntityName:entityName predicate:predicate];
for (NSManagedObject *managedObject in items)
{
[self.managedObjectContext deleteObject:managedObject];
}
NSError *error = nil;
if (![self.managedObjectContext save:&error])
{
NSLog(@"Error deleting %@ - error:%@", entityName, [error localizedDescription]);
return NO;
}
return YES;
}
具体例子就不举了,应该很简单了。
以上。