18.0~18.10 Core Data
来源:互联网 发布:递归算法执行过程 编辑:程序博客网 时间:2024/06/10 07:43
18.0. Introduction(Core Data)
core data 是一个很强大的框架,它使得程序员能够以对象的形式保存和管理对象。传统做法,程序员只能使用oc自带的归档能力保存数据,或是手动写入数据。利用core data,programer可以更有效的管理数据。
core data 隐藏了底层的实现细节。programer只需要知道它提供的api。不过理解core data的结构,以及其工作原理很重要。
使用新的llvm编译器时,你只需引入头文件
#import <CoreData/CoreData.h>
首先需要了解一下概念
Persistent store:磁盘上代表实际数据的对象,我们不直接使用这个对象
Persistent store coordinator:从Persistent store中读取和写入信息的协调员。是连接managed object context
和Persistent store的桥梁
Managed object model (MOM):磁盘上的代表数据模型的文件。类似数据库架构的东西
Managed object:保存core data的入口类。对应传统的数据库上的表。NSManagedObject类型。其实例都在managed object contexts上,通过persistent store coordinator才能保存到persistent store
Managed object context (MOC):这是一块虚拟的板,奇怪吧,我们在内存中创建core data 对象并设置属性。这些工作都是在MOC上完成的。mod保存我们对Managed object的所有操作,并且允许回退。Managed object对于moc,就像桌上的一个玩具,你可以移动它,毁了它,把它扔出桌面,或是增加新的玩具。桌子就是moc,当你操作完成后,你可以保存moc状态,保存的操作将通过persistent store coordinator
保存persistent store信息,并序列化到磁盘
想在工程中使用core data ,直接在创建的时候勾选use core data(不是所有模板都有的,master-Detail、utility、empty有) ,一旦你勾选use core data,app delegate 将增加以下属性
NSManagedObjectContext *managedObjectContext;
NSManagedObjectModel *managedObjectModel;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
18.1. Creating a Core Data Model with Xcode
可视化设计数据模型
1,找到xcdatamodel文件,点击打开
2,记住Entity相当于数据库中的表,Attribute是表中的列
3,Xcode底部找到加号按钮,长按,在弹出的菜单中选择add Entity,Entities那边将增加一项
4,将新增的项改名Person
5,点击Person,在Attributes面板中通过加号增加下面几项
firstName(string类型)
lastName(string类型)
age(Interger32类型)
6,显示右边栏
7,点击firstName,lastName不勾选optional,点击age勾选optional。
8,保存
18.2. Generating Class Files for Core Data Entities
生产类文件
先完成上一节操作
1,点击xcdatamodel文件
2,选择Person entity
3,File->New File
4,IOS->Core Data->NSManagedObject subclass->next
5,选择你想要保存的managedobjectmodel文件,如:cookbook_7_18_2(以xcdatamodel为后缀的那个文件),然后Next
6,目前我们只创建Person Entity,所以这里只有Person一项,勾选->next
7,保存界面,确保你的target是勾选的,否则,别人可能用不了它,create
OK,导出来了,看下
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface Person :NSManagedObject
@property (nonatomic,retain) NSString * firstName;
@property (nonatomic,retain) NSString * lastName;
@property (nonatomic,retain) NSNumber * age;
@end
@implementation Person
@dynamic firstName;
@dynamic lastName;
@dynamic age;
@end
18.3. Creating and Saving Data Using Core Data
实例化
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
Person *newPerson = [NSEntityDescription
insertNewObjectForEntityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
if (newPerson != nil){
newPerson.firstName =@"Anthony";
newPerson.lastName =@"Robbins";
newPerson.age =@51;
NSError *savingError = nil;
if ([self.managedObjectContextsave:&savingError]){
NSLog(@"Successfully saved the context.");
} else {
NSLog(@"Failed to save the context. Error = %@", savingError);
}
} else {
NSLog(@"Failed to create the new person.");
}
self.window = [[UIWindowalloc] initWithFrame:[[UIScreenmainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColorwhiteColor];
[self.windowmakeKeyAndVisible];
return YES;
}
打印:
2014-07-23 10:01:02.485 cookbook7_18_1[386:a0b] Successfully saved the context.
2014-07-23 10:01:02.489 cookbook7_18_1[386:a0b] Application windows are expected to have a root view controller at the end of application launch
NSEntityDescription的类方法 insertNewObject ForEntityForName:inManagedObjectContext:将从ManagedObjectContext参数中寻找对应第二个参数的entity.如果找到,则返回一个实例,这好比在数据表中插入一条数据。插入数据后要记得提交保存。
如果第二个参数所标记的entity不存在,则会抛出一个NSInternalInconsistencyException异常,比如把@"Person"改成@"Person1",运行
打印:
2014-07-23 10:07:45.250 cookbook7_18_1[408:a0b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an entity named 'Person1' in this model.'
18.4. Reading Data from Core Data
读取数据
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[selfcreateNewPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
age:51];
[selfcreateNewPersonWithFirstName:@"Richard"
lastName:@"Branson"
age:61];
/* Tell the request that we want to read the
contents of the Person entity */
/* Create the fetch request first */
NSFetchRequest *fetchRequest = [[NSFetchRequestalloc]
initWithEntityName:@"Person"];
NSError *requestError = nil;
/* And execute the fetch request on the context */
NSArray *persons = [self.managedObjectContextexecuteFetchRequest:fetchRequest error:&requestError];
/* Make sure we get the array */
if ([persons count] > 0){
/* Go through the persons array one by one */
NSUInteger counter = 1;
for (Person *thisPerson in persons){
NSLog(@"Person %lu First Name = %@", (unsignedlong)counter,thisPerson.firstName);
NSLog(@"Person %lu Last Name = %@", (unsignedlong)counter,thisPerson.lastName);
NSLog(@"Person %lu Age = %ld", (unsignedlong)counter,(unsignedlong)[thisPerson.ageunsignedIntegerValue]); counter++;
}
} else {
NSLog(@"Could not find any Person entities in the context.");
}
self.window = [[UIWindowalloc] initWithFrame:[[UIScreenmainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColorwhiteColor];
[self.windowmakeKeyAndVisible];
return YES;
}
- (BOOL) createNewPersonWithFirstName:(NSString *)paramFirstName
lastName:(NSString *)paramLastName
age:(NSUInteger)paramAge{
BOOL result = NO;
if ([paramFirstName length] == 0 ||
[paramLastNamelength] == 0){
NSLog(@"First and Last names are mandatory.");
return NO;
}
Person *newPerson = [NSEntityDescription
insertNewObjectForEntityForName:@"Person"
inManagedObjectContext:self.managedObjectContext];
if (newPerson == nil){
NSLog(@"Failed to create the new person.");
return NO;
}
newPerson.firstName = paramFirstName;
newPerson.lastName = paramLastName;
newPerson.age =@(paramAge);
NSError *savingError = nil;
if ([self.managedObjectContextsave:&savingError]){
return YES;
} else {
NSLog(@"Failed to save the new person. Error = %@", savingError);
}
return result;
}
打印:
2014-07-23 10:16:22.406 cookbook7_18_1[433:a0b] Person 1 First Name = Anthony
2014-07-23 10:16:22.407 cookbook7_18_1[433:a0b] Person 1 Last Name = Robbins
2014-07-23 10:16:22.407 cookbook7_18_1[433:a0b] Person 1 Age = 51
2014-07-23 10:16:22.408 cookbook7_18_1[433:a0b] Person 2 First Name = Anthony
2014-07-23 10:16:22.408 cookbook7_18_1[433:a0b] Person 2 Last Name = Robbins
2014-07-23 10:16:22.409 cookbook7_18_1[433:a0b] Person 2 Age = 51
2014-07-23 10:16:22.409 cookbook7_18_1[433:a0b] Person 3 First Name = Richard
2014-07-23 10:16:22.410 cookbook7_18_1[433:a0b] Person 3 Last Name = Branson
2014-07-23 10:16:22.410 cookbook7_18_1[433:a0b] Person 3 Age = 61
2014-07-23 10:16:22.413 cookbook7_18_1[433:a0b] Application windows are expected to have a root view controller at the end of application launch
为什么有3个呢?因为在上一节我们也保存了一个
NSFetchRequest相当于sélect 语句,你可以指定哪些行,符合什么条件的数据返回。
18.5. Deleting Data from Core Data
删除数据
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[selfcreateNewPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
age:51];
[selfcreateNewPersonWithFirstName:@"Richard"
lastName:@"Branson"
age:61];
/* Create the fetch request first */
NSFetchRequest *fetchRequest = [[NSFetchRequestalloc]
initWithEntityName:@"Person"];
NSError *requestError = nil;
/* And execute the fetch request on the context */
NSArray *persons =
[self.managedObjectContextexecuteFetchRequest:fetchRequest
error:&requestError];
/* Make sure we get the array */
if ([persons count] > 0){
/* Delete the last person in the array */
Person *lastPerson = [persons lastObject];
[self.managedObjectContextdeleteObject:lastPerson];
NSError *savingError = nil;
if ([self.managedObjectContextsave:&savingError]){
NSLog(@"Successfully deleted the last person in the array.");
} else {
NSLog(@"Failed to delete the last person in the array.");
}
} else {
NSLog(@"Could not find any Person entities in the context.");
}
self.window = [[UIWindowalloc] initWithFrame:[[UIScreenmainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColorwhiteColor];
[self.windowmakeKeyAndVisible];
return YES;
}
打印:
2014-07-23 11:16:23.588 cookbook7_18_1[527:a0b] Successfully deleted the last person in the array.
2014-07-23 11:16:23.591 cookbook7_18_1[527:a0b] Application windows are expected to have a root view controller at the end of application launch
可以通过deleteObject:来删除数据,但是这个方法没有参数,也没有返回值,我们不知道到底删除成功了没有。不过我们可以通过被删除对象的isDeleted方法来判断。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[selfcreateNewPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
age:51];
[selfcreateNewPersonWithFirstName:@"Richard"
lastName:@"Branson"
age:61];
/* Create the fetch request first */
NSFetchRequest *fetchRequest = [[NSFetchRequestalloc]
initWithEntityName:@"Person"];
NSError *requestError = nil;
/* And execute the fetch request on the context */
NSArray *persons =
[self.managedObjectContextexecuteFetchRequest:fetchRequest
error:&requestError];
/* Make sure we get the array */
if ([persons count] > 0){
/* Delete the last person in the array */
Person *lastPerson = [persons lastObject];
[self.managedObjectContextdeleteObject:lastPerson];
if ([lastPerson isDeleted]){
NSLog(@"Successfully deleted the last person...");
NSError *savingError = nil;
if ([self.managedObjectContextsave:&savingError]){
NSLog(@"Successfully saved the context.");
} else {
NSLog(@"Failed to save the context.");
}
} else {
NSLog(@"Failed to delete the last person.");
}
} else {
NSLog(@"Could not find any Person entities in the context.");
}
self.window = [[UIWindowalloc] initWithFrame:[[UIScreenmainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColorwhiteColor];
[self.windowmakeKeyAndVisible];
return YES;
}
打印:
2014-07-23 11:25:20.939 cookbook7_18_1[550:a0b] Successfully deleted the last person...
2014-07-23 11:25:20.940 cookbook7_18_1[550:a0b] Successfully saved the context.
2014-07-23 11:25:20.943 cookbook7_18_1[550:a0b] Application windows are expected to have a root view controller at the end of application launch
18.6. Sorting Data in Core Data
给数据排序
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[selfcreateNewPersonWithFirstName:@"Richard"
lastName:@"Branson"
age:61];
[selfcreateNewPersonWithFirstName:@"Anthony"
lastName:@"Robbins"
age:51];
/* Create the fetch request first */
NSFetchRequest *fetchRequest = [[NSFetchRequestalloc]
initWithEntityName:@"Person"];
NSSortDescriptor *ageSort =
[[NSSortDescriptoralloc] initWithKey:@"age"
ascending:YES];
NSSortDescriptor *firstNameSort =
[[NSSortDescriptoralloc] initWithKey:@"firstName"
ascending:YES];
fetchRequest.sortDescriptors =@[ageSort, firstNameSort];
NSError *requestError = nil;
/* And execute the fetch request on the context */
NSArray *persons =
[self.managedObjectContextexecuteFetchRequest:fetchRequest
error:&requestError];
for (Person *person in persons){
NSLog(@"First Name = %@", person.firstName);
NSLog(@"Last Name = %@", person.lastName);
NSLog(@"Age = %lu", (unsignedlong)[person.ageunsignedIntegerValue]);
// [self.managedObjectContext deleteObject:person];
// [self.managedObjectContext save:nil];
}
self.window = [[UIWindowalloc] initWithFrame:[[UIScreenmainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColorwhiteColor];
[self.windowmakeKeyAndVisible];
return YES;
}
2014-07-23 11:30:13.868 cookbook7_18_1[599:a0b] First Name = Anthony
2014-07-23 11:30:13.869 cookbook7_18_1[599:a0b] Last Name = Robbins
2014-07-23 11:30:13.870 cookbook7_18_1[599:a0b] Age = 51
2014-07-23 11:30:13.870 cookbook7_18_1[599:a0b] First Name = Richard
2014-07-23 11:30:13.871 cookbook7_18_1[599:a0b] Last Name = Branson
2014-07-23 11:30:13.871 cookbook7_18_1[599:a0b] Age = 61
2014-07-23 11:30:13.874 cookbook7_18_1[599:a0b] Application windows are expected to have a root view controller at the end of application launch
18.7. Boosting Data Access in Table Views
列表展示数据信息给用户
使用NSFetchedResultsController.
为什么使用NSFetchedResultsController.
1,对数据的任何修改都将直接反应到界面上
2,可以更有效的管理缓存,可以指定内存中只保留N个对象实例
3,可以轻松的使用列表视图展示数据
例子下载:
PersonsListTableViewController.m文件 (列表文件)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo =self.frc.sections[section];
return sectionInfo.numberOfObjects;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell =nil;
cell = [tableView dequeueReusableCellWithIdentifier:PersonTableViewCell
forIndexPath:indexPath];
Person *person = [self.frcobjectAtIndexPath:indexPath];
cell.textLabel.text = [person.firstNamestringByAppendingFormat:@" %@", person.lastName];
cell.detailTextLabel.text = [NSStringstringWithFormat:@"Age: %lu",(unsignedlong)[person.ageunsignedIntegerValue]]; return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
Person *personToDelete = [self.frcobjectAtIndexPath:indexPath];
AppDelegate *appDelegate = [[UIApplicationsharedApplication] delegate];
[[appDelegatemanagedObjectContext] deleteObject:personToDelete];
if ([personToDelete isDeleted]){
NSError *savingError = nil;
if ([[appDelegate managedObjectContext]save:&savingError]){
NSLog(@"Successfully deleted the object");
} else {
NSLog(@"Failed to save the context with error = %@", savingError);
}
}
}
-(void)constructFetchResultController{
/* Create the fetch request first */
NSFetchRequest *fetchRequest = [[NSFetchRequestalloc]
initWithEntityName:@"Person"];
NSSortDescriptor *ageSort =[[NSSortDescriptoralloc] initWithKey:@"age"
ascending:YES];
NSSortDescriptor *firstNameSort =[[NSSortDescriptoralloc] initWithKey:@"firstName"
ascending:YES];
fetchRequest.sortDescriptors =@[ageSort, firstNameSort];
AppDelegate * appDelegate = [[UIApplicationsharedApplication] delegate];
self.frc =[[NSFetchedResultsControlleralloc]
initWithFetchRequest:fetchRequest
managedObjectContext: appDelegate.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
self.frc.delegate =self;
NSError *fetchingError = nil;
if ([self.frcperformFetch:&fetchingError]){
NSLog(@"Successfully fetched.");
} else {
NSLog(@"Failed to fetch.");
}
}
#pragma mark - NSFetchedResultsControllerDelegate
- (void) controllerWillChangeContent:(NSFetchedResultsController *)controller{
[self.tableViewbeginUpdates];
}
- (void) controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath{
if (type ==NSFetchedResultsChangeDelete){
[self.tableViewdeleteRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
elseif (type ==NSFetchedResultsChangeInsert){
[self.tableViewinsertRowsAtIndexPaths:@[newIndexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
- (void) controllerDidChangeContent:(NSFetchedResultsController *)controller{
[self.tableViewendUpdates];
}
ViewController.m (新增person文件)
- (IBAction)OKButtonAction:(id)sender {
[selfcreateNewPerson:nil];
}
- (void) createNewPerson:(id)paramSender{
AppDelegate *appDelegate = [[UIApplicationsharedApplication] delegate];
NSManagedObjectContext *managedObjectContext =
appDelegate.managedObjectContext;
Person *newPerson =
[NSEntityDescriptioninsertNewObjectForEntityForName:@"Person"
inManagedObjectContext:managedObjectContext];
if (newPerson != nil){
newPerson.firstName =self.textFieldFirstName.text;
newPerson.lastName =self.textFieldLastName.text;
newPerson.age =@([self.textFieldAge.textintegerValue]);
NSError *savingError = nil;
if ([managedObjectContext save:&savingError]){ [self.navigationControllerpopViewControllerAnimated:YES];
} else {
NSLog(@"Failed to save the managed object context.");
}
} else {
NSLog(@"Failed to create the new person object.");
}
}
从例子中可以发现,我们只需新增删除数据,不需要reloaddata,列表就会自动更新
18.8. Implementing Relationships in Core Data
实现实体间的关系
生成文件后:
Employee.h文件
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Manager;
@interface Employee :NSManagedObject
@property (nonatomic,retain) NSNumber * age;
@property (nonatomic,retain) NSString * firstName;
@property (nonatomic,retain) NSString * lastName;
@property (nonatomic,retain) Manager *manager;
@end
Employee.m文件
#import "Employee.h"
#import "Manager.h"
@implementation Employee
@dynamic age;
@dynamic firstName;
@dynamic lastName;
@dynamic manager;
@end
Manager.h文件
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Employee;
@interface Manager :NSManagedObject
@property (nonatomic,retain) NSNumber * age;
@property (nonatomic,retain) NSString * lastName;
@property (nonatomic,retain) NSString * firstName;
@property (nonatomic,retain) NSSet *employees;
@end
@interface Manager (CoreDataGeneratedAccessors)
- (void)addEmployeesObject:(Employee *)value;
- (void)removeEmployeesObject:(Employee *)value;
- (void)addEmployees:(NSSet *)values;
- (void)removeEmployees:(NSSet *)values;
@end
Manager.m文件
#import "Manager.h"
#import "Employee.h"
@implementation Manager
@dynamic age;
@dynamic lastName;
@dynamic firstName;
@dynamic employees;
@end
18.9. Fetching Data in the Background
后台获取数据
1,创建新的managed object context
2,使用persormBlock获取数据
3,利用dispatch_async切换到主线程
4,利用主线程的managed object context的objectWithID: 方法获得对象
注意:
1,最好不要用主线程去获取数据,数据多的话影响用户体验
2,一个应用里面可以有很多的contexts,但是你不能在他们之间传递managed objects,因为他不是线程安全的。正确的做法是后台获取persistent IDs,主线程根据ID获取对象。为什么这样做呢,因为根据ID检索对象,比直接去检索快得多。
例子见此
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSFetchRequest *fetchRequest = [[NSFetchRequestalloc]
initWithEntityName:@"Person"];
NSError *requestError = nil;
/* And execute the fetch request on the context */
NSArray *persons =
[self.managedObjectContextexecuteFetchRequest:fetchRequest
error:&requestError];
//删除所有
// NSLog(@"persons.count=%d",persons.count);
// for (Person * person in persons) {
// [self.managedObjectContext deleteObject:person];
// }
// [self saveContext];
//新增
if (persons.count <10) {
[selfpopulateDatabase:10];
}
// Override point for customization after application launch.
__weak NSManagedObjectContext *mainContext =self.managedObjectContext;
__weak AppDelegate *weakSelf =self;
__block NSMutableArray *mutablePersons =nil;
/* Set up the background context */
NSManagedObjectContext *backgroundContext =[[NSManagedObjectContextalloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
backgroundContext.persistentStoreCoordinator =self.persistentStoreCoordinator;
/* Issue a block on the background context */
[backgroundContextperformBlock:^{
NSError *error = nil;
NSArray *personIds = [backgroundContext
executeFetchRequest:[weakSelf newFetchRequest]
error:&error];
if (personIds != nil && error ==nil){
mutablePersons = [[NSMutableArrayalloc] initWithCapacity:personIds.count];
/* Now go on the main context and get the objects on that
context using their IDs */
dispatch_async(dispatch_get_main_queue(), ^{
for (NSManagedObjectID *personIdin personIds){
Person *person = (Person *)[mainContextobjectWithID:personId];
[mutablePersonsaddObject:person];
}
[weakSelfprocessPersons:mutablePersons];
});
}else {
NSLog(@"Failed to execute the fetch request.");
}
}];
return YES;
}
#pragma mark - 18.9
- (NSFetchRequest *) newFetchRequest{
NSFetchRequest *request = [[NSFetchRequestalloc]
initWithEntityName:
NSStringFromClass([Personclass])];
request.fetchBatchSize =20;
request.predicate =
[NSPredicatepredicateWithFormat:@"(age >= 100) AND (age <= 200)"];
request.resultType =NSManagedObjectIDResultType;
return request;
}
- (void) processPersons:(NSArray *)paramPersons{
for (Person *personin paramPersons){
NSLog(@"First name = %@, last name = %@, age = %ld",
person.firstName,
person.lastName,(long)person.age.integerValue);
}
}
- (void) populateDatabase:(int)count{
for (NSUInteger counter =0; counter < count; counter++){
Person *person = [NSEntityDescription
insertNewObjectForEntityForName:NSStringFromClass([Personclass])
inManagedObjectContext:self.managedObjectContext];
person.firstName = [NSStringstringWithFormat:@"First name %lu", (unsignedlong)counter];
person.lastName = [NSStringstringWithFormat:@"Last name %lu", (unsignedlong)counter];
person.age =@(counter);
}
NSError *error = nil;
if ([self.managedObjectContextsave:&error]){
NSLog(@"Managed to populate the database.");
}else {
NSLog(@"Failed to populate the database. Error = %@", error);
}
}
18.10. Using Custom Data Types in Your Core Data Model
core data里面使用自定义数据类型
有些数据类型,如UIColor,不能作为core data的数据类型怎么办呢?使用transformable属性
比如要创建模型Laptop.它有两个属性一个是model(NSString),另一个是 color(UIColor),core data 不支持UIColor。
我们需要创建NSValueTransformer的子类,比如:ColorTransformer.
我们需要实现以下步骤
1,覆写allowsReverseTransformation返回Yes。意思是告诉Core Data,你可以实现color和Data的互转
2,覆写transformedValueClass,返回NSData类名。意思是告诉Core Data,你会把你自定义的值转化成这个类,这里表示你会把UIColor转化成NSData。
3,覆写transformedValue:把传入的值(UIColor)转换成NSData
4,覆写reverseTransformedValue:把NSData转化成UIColor
ColorTransformer类
#import <Foundation/Foundation.h>
@interface ColorTransformer :NSValueTransformer
@end
#import "ColorTransformer.h"
@implementation ColorTransformer
+ (BOOL) allowsReverseTransformation{
return YES;
}
+ (Class) transformedValueClass{
return [NSData class];
}
- (id) transformedValue:(id)value{
/* Transform color to data */
UIColor *color = (UIColor *)value;
CGFloat red, green, blue, alpha;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
CGFloat components[4] = {red, green, blue, alpha};
NSData *dataFromColors = [[NSData alloc] initWithBytes:components
length:sizeof(components)];
return dataFromColors;
}
- (id) reverseTransformedValue:(id)value{
/* Transform back from data to color */
NSData *data = (NSData *)value;
CGFloat components[4] = {0.0f,0.0f, 0.0f,0.0f};
[data getBytes:components length:sizeof(components)];
UIColor *color = [UIColor colorWithRed:components[0]
green:components[1]
blue:components[2]
alpha:components[3]];
return color;
}
@end
Laptop模型
生产的Laptop.h文件
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface Laptop :NSManagedObject
@property (nonatomic,retain) id color;
@property (nonatomic,retain) NSString * model;
@end
为了让编译器帮我们防错,我们可以手动把color的类型改下,结果就是
@interface Laptop :NSManagedObject
@property (nonatomic,retain) UIColor* color;
@property (nonatomic,retain) NSString * model;
@end
- 18.0~18.10 Core Data
- core data
- Core Data
- Core Data
- Core Data
- Core data
- Core Data
- Core Data
- Core Data
- Core Data
- core data
- Core Data
- Core Data
- Core Data
- Core Data
- core data
- Core Data
- Core Data
- C++ primer(第五版) 练习 3.30 个人 见解
- Linux下如何将数据库脚本文件从sh格式变为sql格式
- Android应用如何实现换肤功能
- 【原创】《Linux设备驱动程序》学习之循序渐进 --- 与硬件通信
- 小写金额变大写-局限于20亿
- 18.0~18.10 Core Data
- Android 去除Tabhost自带黑线
- linux设备驱动中file_operations结构体分析
- 思考一种高性能的服务器处理框架
- Truncate Table 用法
- spring MVC和Mybatis集成
- python的logging模块handle的子类
- HDU 1114 Piggy-Bank【完全背包】
- [教程] CSS3 选择器——基本选择器(一)