18.0~18.10 Core Data

来源:互联网 发布:递归算法执行过程 编辑:程序博客网 时间:2024/06/10 07:43

18.0. IntroductionCore 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 contextobjectWithID: 方法获得对象

注意:

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


0 0