码迷,mamicode.com
首页 > 移动开发 > 详细

IOS开发之--Core Data的使用(进阶)

时间:2015-08-16 11:58:19      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:

CoreData的使用(进阶)

本次目标是创建一个应用程序,可以记录每次你保存的经纬度坐标,并且可以对这些坐标(我们保存为一个Event实体)进行编辑。

建立工程

步骤

 

  1. 创建一个Empty Application,起名叫Locations,选择Devices为iPhone,并且使用ARC;
  2. 添加CoreLocation.framework;
  3. 添加一个Storyboard文件,并在工程属性中选择Main Storyboard为这个文件;
  4. 至此,操作步骤完成。

对工程的理解

以上步骤完成后,我们的工程中多了很多文件,我们一一讲解如下:

 

  1. 应用的代理类AppDelegate(.h和.m文件);
  2. 一个.xib界面描述文件;
  3. 一个Core Data的模型文件.xcdatamodelId;
  4. 这个工程还引用了CoreLocation.framework;

 

我们还能看到对于AppDelegate.h,会自动生成相关Core Data的处理:

 

  1. @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;  
  2. @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;  
  3. @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;  
  4.   
  5. - (void)saveContext;  
  6. - (NSURL *)applicationDocumentsDirectory;  


就像方法暗指的那样,applicationDocumentsDirectory方法返回的是app的文档路径,数据将被保存在那里。

 

 

Core Data Stack

这里的stack指的是Core Data framework中一系列对象的集合,这些对象协同工作,将模型从文件中取出,或者写入到文件中。从类比的角度说,Core Data可以被看为一个数据库,保存了记录和表(Core Data中的数据有可能真的被保存在数据库中,例如SQLite,但是这个不是一定的)。一个最简单和最频繁使用的Core Data Stack结构如下(可以和上一篇文章印证):

技术分享

其中你最常用的是Managed Object Context和其包含的Managed Object对象。

 

Managed Object和Managed Object Context

Managed Object是一个NSManagedObject或者他的子类的对象。他代表了在Store中保存的一个对象的记录,所以他是一个由Core Data管理的模型。Managed Object对象管理应用中使用的数据,例如:一个人力资源管理系统中的部门和雇员信息;一个绘图程序中的形状、文本和分组信息;一个音乐程序中的音轨信息。一个Managed Object始终和一个Managed Object Context相关联。

 

Managed Object Context是一个NSManagedObjectContext类的实例。一个context代表了一个应用中与数据有关的内存区域。context的主要职责是用来管理managed object对象。Context对象是你的应用的控制中枢,负责生命周期管理到验证、Managed Object间的关系维护、重做和取消等功能。

 

当你新建一个Managed Object的时候,首先要将其放入Context中。你将对象取回(fetch)的时候,同样将其存入context对象。所有的操作都在内存中,一直到你通过commit提交你的修改为止。

 

下面的图演示了记录(record)和对象(object)的关系,注意有个Nigel对象没有保存,所以Store中的salary仍然是50000,另外有两个对象未纳入context管理。

技术分享

 

Managed Object Model

Managed Object Model是一个NSManagedObjectModel类的实例,他描述了数据库的Schema,所以你的数据能够保存到Store中。一个模型(model)是一个实体对象模型(NSEntityDescription)的集合。一个实体描述根据实体的名字描述一个实体,类名,及其属性。

 

下图描述了模型的实体描述、数据库中表和Managed Object中单个对象的关系:

技术分享

 

每个Managed Object都有对应的实体描述。

Core Data使用模型来在应用的managed object和数据库的记录中描述映射关系。所以一定要对改变模型(描述)小心处理。Core Data无法使用你之前的模型来使用现在的数据。(实际上需要通过版本管理来处理这种变更,而不是完全不能处理)

 

Persistent Store Coordinator

PSC扮演的角色是告诉Core Data如何管理数据。大多数时候你完全不用关心这个对象。

 

一个PSC是NSPersistentStoreCoordinator类的一个实例,他管理了一系列的persistent object store。一个persistent object stores代表一个需要序列化的外部文件或数据库。实际上Core Data支持多种持久化数据类型,甚至你可以声明自己的数据文件类型。

 

在iOS中,一般你仅有一个store,但在复杂的应用(例如OSX)中你可能有多个保存实体的store,所以PSC需要来管理这些store,当你需要取回数据时,PSC将取回所有结果。

 

下图模拟了coordinator的工作角色,实际情况通常不会这么复杂:

技术分享

 

 

Table View Controller

这一小节主要实现Table View Controller相关功能。下面我们一步一步来执行以下步骤,:

 

  1. 在Storyboard中创建一个Table View,并将其嵌入到Navigation Controller中;
  2. 添加两个按钮到Navigation Bar上面,并且将左边按钮的Identifier改为Edit,右边Identifier修改为Add;
  3. 添加一个UITableViewController的子类,名字为LocationsListViewController;
  4. 添加对位置信息的支持,所以LocationsListViewController的头文件变为:
    1. #import <UIKit/UIKit.h>  
    2. #import <CoreLocation/CoreLocation.h>  
    3.   
    4. @interface LocationsListViewController : UITableViewController <CLLocationManagerDelegate>  
    5.   
    6. @property (nonatomic, retain) NSMutableArray *eventsArray;  
    7. @property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;  
    8.   
    9. @property (nonatomic, retain) CLLocationManager *locationManager;  
    10. @property (nonatomic, retain) UIBarButtonItem *addButton;  
    11.   
    12. @end  
  5. 实现文件中对于location获取相关代码实现如下:
    1. @implementation LocationsListViewController  
    2.   
    3. @synthesize eventsArray;  
    4. @synthesize locationManager;  
    5. @synthesize managedObjectContext;  
    6. @synthesize addButton;  
    7.   
    8.   
    9. - (CLLocationManager *)locationManager {  
    10.       
    11.     if (locationManager != nil) {  
    12.         return locationManager;  
    13.     }  
    14.       
    15.     locationManager = [[CLLocationManager alloc] init];  
    16.     locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;  
    17.     locationManager.delegate = self;  
    18.       
    19.     return locationManager;  
    20. }  
    21.   
    22. - (void)locationManager:(CLLocationManager *)manager  
    23.     didUpdateToLocation:(CLLocation *)newLocation  
    24.            fromLocation:(CLLocation *)oldLocation {  
    25.     addButton.enabled = YES;  
    26. }  
    27.   
    28. - (void)locationManager:(CLLocationManager *)manager  
    29.        didFailWithError:(NSError *)error {  
    30.     addButton.enabled = NO;  
    31. }  
    32.   
    33. - (id)initWithStyle:(UITableViewStyle)style  
    34. {  
    35.     self = [super initWithStyle:style];  
    36.     if (self) {  
    37.         // Custom initialization  
    38.     }  
    39.     return self;  
    40. }  
    41.   
    42. - (void)viewDidLoad  
    43. {  
    44.     [super viewDidLoad];  
    45.   
    46.     // Set the title.  
    47.     self.title = @"Locations";  
    48.       
    49.     // Set up the buttons.  
    50.     self.navigationItem.leftBarButtonItem = self.editButtonItem;  
    51.       
    52.     addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd  
    53.                                                               target:self action:@selector(addEvent)];  
    54.     addButton.enabled = NO;  
    55.     self.navigationItem.rightBarButtonItem = addButton;  
    56.       
    57.     // Start the location manager.  
    58.     [[self locationManager] startUpdatingLocation];  
    59. }  

    这里剩下addEvent未实现。
  6. 接着我们去AppDelegate类,将didFinishLaunchingWithOptions修改为:
    1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  
    2. {  
    3.     return YES;  
    4. }  
  7. 至此,本阶段工作完成,运行程序显示如下界面:

技术分享

 

Managed Object and Model

这一部分比较简单,步骤如下:

 

  1. 打开Locations.xcdatamodeld文件,Add Entity,名字叫Event;
  2. 分别添加属性如下图:
    技术分享
  3. 创建自定义的Managed Object类。原则上你可以直接使用NSManagedObject,但实际上大部分情况下都会使用他的子类,好处如下:
    • 从开发工具获得更好的支持。例如属性存取方法的自动完成、编译时类型和符号的检测等;
    • 支持实体的自定义方法。大多数情况下你希望实体提供特殊的逻辑,例如自定义的验证、或者衍生的属性等。例如,一个Person实体的hasDriversLicense属性在age属性不到17时不可能是true(所以会有一个校验),或者一个fullName方法返回的是firstName和lastName的一个合适的拼接。
  4. 我们选择Event这个Entity,然后新建一个文件,选择Core Data分类中的NSManagedObject subclass。
    技术分享
  5. 我们可以看到自动生成的代码中包含了Event这个实体映射的域模型了。

 

 

Adding Events

这一小节的目标是添加事件并且将其显示在ListView中。

 

  1. 在story board中将我们的list view和我们之前创建的LocationsListViewController相关联;
  2. 在LocationsListViewController中添加方法:
    1. - (void)addEvent {  
    2.     // Get the Current Location  
    3.     CLLocation *location = [locationManager location];  
    4.     if (!location) {  
    5.         return;  
    6.     }  
    7.       
    8.     // Create and configure a new instance of the Event entity.  
    9.     Event *event = (Event *)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:managedObjectContext];  
    10.       
    11.     CLLocationCoordinate2D coordinate = [location coordinate];  
    12.     [event setLatitude:[NSNumber numberWithDouble:coordinate.latitude]];  
    13.     [event setLongitude:[NSNumber numberWithDouble:coordinate.longitude]];  
    14.     [event setCreationDate:[NSDate date]];  
    15.       
    16.     // Save the New Event  
    17.     NSError *error = nil;  
    18.     if (![managedObjectContext save:&error]) {  
    19.         // Handle the error.  
    20.         NSLog(@"Save Event failed.");  
    21.         return ;  
    22.     }  
    23.       
    24.     // Update the Events Array and the Table View  
    25.     [eventsArray insertObject:event atIndex:0];  
    26.     NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];  
    27.     [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]  
    28.                           withRowAnimation:UITableViewRowAnimationFade];  
    29.     [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];  
    30. }  
  3. 其余涉及到Table View的显示代码如下(注意设置Table View的Cell的Identifier为Cell,区分大小写;同时将Cell的Style设置为Right Detail):
    1. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView  
    2. {  
    3.     // Return the number of sections.  
    4.     return 1;  
    5. }  
    6.   
    7. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section  
    8. {  
    9.     return [eventsArray count];  
    10. }  
    11.   
    12. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  
    13. {  
    14.     // A date formatter for the time stamp.  
    15.     static NSDateFormatter *dateFormatter = nil;  
    16.     if (dateFormatter == nil) {  
    17.         dateFormatter = [[NSDateFormatter alloc] init];  
    18.         [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];  
    19.         [dateFormatter setDateStyle:NSDateFormatterMediumStyle];  
    20.     }  
    21.       
    22.     // A number formatter for the latitude and longitude.  
    23.     static NSNumberFormatter *numberFormatter = nil;  
    24.     if (numberFormatter == nil) {  
    25.         numberFormatter = [[NSNumberFormatter alloc] init];  
    26.         [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];  
    27.         [numberFormatter setMaximumFractionDigits:3];  
    28.     }  
    29.       
    30.     static NSString *CellIdentifier = @"Cell";  
    31.       
    32.     // Dequeue or create a new cell.  
    33.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];  
    34.     if (cell == nil) {  
    35.         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];  
    36.     }  
    37.       
    38.     Event *event = (Event *)[eventsArray objectAtIndex:indexPath.row];  
    39.       
    40.     cell.textLabel.text = [dateFormatter stringFromDate:[event creationDate]];  
    41.       
    42.     NSString *string = [NSString stringWithFormat:@"%@, %@",  
    43.                         [numberFormatter stringFromNumber:[event latitude]],  
    44.                         [numberFormatter stringFromNumber:[event longitude]]];  
    45.     cell.detailTextLabel.text = string;  
    46.       
    47.     return cell;  
    48. }  
  4. 还要实现一个getManagedObjectContext的方法:
    1. - (NSManagedObjectContext *)getManagedObjectContext {  
    2.     NSManagedObjectContext *context = nil;  
    3.     id delegate = [[UIApplication sharedApplication] delegate];  
    4.     if ([delegate performSelector:@selector(managedObjectContext)]) {  
    5.         context = [delegate managedObjectContext];  
    6.     }  
    7.     return context;  
    8. }  
  5. 最后在viewDidLoad方法最末尾加上eventArray和context的初始化代码:
    1. eventsArray = [[NSMutableArray alloc] init];  
    2. managedObjectContext = self.getManagedObjectContext;  
  6. 运行程序,添加event看看效果。

 

Fetching Events

获取数据的步骤比较简单:

 

  1. 创建请求;
  2. 设置排序条件(可选);
  3. 执行查询;
  4. 将数据放到我们准备好的(可变)数组中;

 

具体代码如下,我们需要创建一个loadData方法,然后在viewDidLoad中执行loadData:

 

  1. -(void)loadData  
  2. {  
  3.     // Create the Request  
  4.     NSFetchRequest *request = [[NSFetchRequest alloc] init];  
  5.     NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectContext];  
  6.     [request setEntity:entity];  
  7.     // Set the Sort Descriptor  
  8.     NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO];  
  9.     NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];  
  10.     [request setSortDescriptors:sortDescriptors];  
  11.     // Execute the Request  
  12.     NSError *error = nil;  
  13.     NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];  
  14.     if (mutableFetchResults == nil) {  
  15.         // Handle the error.  
  16.         NSLog(@"error loading data");  
  17.     }  
  18.     // Finish Up  
  19.     [self setEventsArray:mutableFetchResults];  
  20. }  



 

Deleting Events

删除操作主要是覆盖commitEditingStyle方法,删除Object、删除界面中的显示,代码如下:

 

  1. - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath  
  2. {  
  3.     if (editingStyle == UITableViewCellEditingStyleDelete) {  
  4.         // Delete the managed object at the given index path.  
  5.         NSManagedObject *eventToDelete = [eventsArray objectAtIndex:indexPath.row];  
  6.         [managedObjectContext deleteObject:eventToDelete];  
  7.           
  8.         // Update the array and table view.  
  9.         [eventsArray removeObjectAtIndex:indexPath.row];  
  10.         [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];  
  11.           
  12.         // Commit the change.  
  13.         NSError *error = nil;  
  14.         if (![managedObjectContext save:&error]) {  
  15.             // Handle the error.  
  16.         }  
  17.     }  
  18.     else if (editingStyle == UITableViewCellEditingStyleInsert) {  
  19.         // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view  
  20.     }  
  21. }  



 

 

至此,这个例子完成,运行即可查看效果。

IOS开发之--Core Data的使用(进阶)

标签:

原文地址:http://www.cnblogs.com/cookiess/p/4733711.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!