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

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的处理:

[cpp] view plaincopy

  1. @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
  2. @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
  3. @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
  4. - (void)saveContext;
  5. - (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的头文件变为:

    [cpp] view plaincopy

    1. #import <UIKit/UIKit.h>
    2. #import <CoreLocation/CoreLocation.h>
    3. @interface LocationsListViewController : UITableViewController <CLLocationManagerDelegate>
    4. @property (nonatomic, retain) NSMutableArray *eventsArray;
    5. @property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
    6. @property (nonatomic, retain) CLLocationManager *locationManager;
    7. @property (nonatomic, retain) UIBarButtonItem *addButton;
    8. @end
  5. 实现文件中对于location获取相关代码实现如下:

    [cpp] view plaincopy

    1. @implementation LocationsListViewController
    2. @synthesize eventsArray;
    3. @synthesize locationManager;
    4. @synthesize managedObjectContext;
    5. @synthesize addButton;
    6. - (CLLocationManager *)locationManager {
    7. if (locationManager != nil) {
    8. return locationManager;
    9. }
    10. locationManager = [[CLLocationManager alloc] init];
    11. locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
    12. locationManager.delegate = self;
    13. return locationManager;
    14. }
    15. - (void)locationManager:(CLLocationManager *)manager
    16. didUpdateToLocation:(CLLocation *)newLocation
    17. fromLocation:(CLLocation *)oldLocation {
    18. addButton.enabled = YES;
    19. }
    20. - (void)locationManager:(CLLocationManager *)manager
    21. didFailWithError:(NSError *)error {
    22. addButton.enabled = NO;
    23. }
    24. - (id)initWithStyle:(UITableViewStyle)style
    25. {
    26. self = [super initWithStyle:style];
    27. if (self) {
    28. // Custom initialization
    29. }
    30. return self;
    31. }
    32. - (void)viewDidLoad
    33. {
    34. [super viewDidLoad];
    35. // Set the title.
    36. self.title = @"Locations";
    37. // Set up the buttons.
    38. self.navigationItem.leftBarButtonItem = self.editButtonItem;
    39. addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
    40. target:self action:@selector(addEvent)];
    41. addButton.enabled = NO;
    42. self.navigationItem.rightBarButtonItem = addButton;
    43. // Start the location manager.
    44. [[self locationManager] startUpdatingLocation];
    45. }

    这里剩下addEvent未实现。

  6. 接着我们去AppDelegate类,将didFinishLaunchingWithOptions修改为:

    [cpp] view plaincopy

    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中添加方法:

    [cpp] view plaincopy

    1. - (void)addEvent {
    2. // Get the Current Location
    3. CLLocation *location = [locationManager location];
    4. if (!location) {
    5. return;
    6. }
    7. // Create and configure a new instance of the Event entity.
    8. Event *event = (Event *)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:managedObjectContext];
    9. CLLocationCoordinate2D coordinate = [location coordinate];
    10. [event setLatitude:[NSNumber numberWithDouble:coordinate.latitude]];
    11. [event setLongitude:[NSNumber numberWithDouble:coordinate.longitude]];
    12. [event setCreationDate:[NSDate date]];
    13. // Save the New Event
    14. NSError *error = nil;
    15. if (![managedObjectContext save:&error]) {
    16. // Handle the error.
    17. NSLog(@"Save Event failed.");
    18. return ;
    19. }
    20. // Update the Events Array and the Table View
    21. [eventsArray insertObject:event atIndex:0];
    22. NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    23. [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
    24. withRowAnimation:UITableViewRowAnimationFade];
    25. [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
    26. }
  3. 其余涉及到Table View的显示代码如下(注意设置Table View的Cell的Identifier为Cell,区分大小写;同时将Cell的Style设置为Right Detail):

    [cpp] view plaincopy

    1. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    2. {
    3. // Return the number of sections.
    4. return 1;
    5. }
    6. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    7. {
    8. return [eventsArray count];
    9. }
    10. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    11. {
    12. // A date formatter for the time stamp.
    13. static NSDateFormatter *dateFormatter = nil;
    14. if (dateFormatter == nil) {
    15. dateFormatter = [[NSDateFormatter alloc] init];
    16. [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
    17. [dateFormatter setDateStyle:NSDateFormatterMediumStyle];
    18. }
    19. // A number formatter for the latitude and longitude.
    20. static NSNumberFormatter *numberFormatter = nil;
    21. if (numberFormatter == nil) {
    22. numberFormatter = [[NSNumberFormatter alloc] init];
    23. [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
    24. [numberFormatter setMaximumFractionDigits:3];
    25. }
    26. static NSString *CellIdentifier = @"Cell";
    27. // Dequeue or create a new cell.
    28. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    29. if (cell == nil) {
    30. cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
    31. }
    32. Event *event = (Event *)[eventsArray objectAtIndex:indexPath.row];
    33. cell.textLabel.text = [dateFormatter stringFromDate:[event creationDate]];
    34. NSString *string = [NSString stringWithFormat:@"%@, %@",
    35. [numberFormatter stringFromNumber:[event latitude]],
    36. [numberFormatter stringFromNumber:[event longitude]]];
    37. cell.detailTextLabel.text = string;
    38. return cell;
    39. }
  4. 还要实现一个getManagedObjectContext的方法:

    [cpp] view plaincopy

    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的初始化代码:

    [cpp] view plaincopy

    1. eventsArray = [[NSMutableArray alloc] init];
    2. managedObjectContext = self.getManagedObjectContext;
  6. 运行程序,添加event看看效果。

Fetching Events

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

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

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

[cpp] view plaincopy

  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、删除界面中的显示,代码如下:

[cpp] view plaincopy

  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. // Update the array and table view.
  8. [eventsArray removeObjectAtIndex:indexPath.row];
  9. [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
  10. // Commit the change.
  11. NSError *error = nil;
  12. if (![managedObjectContext save:&error]) {
  13. // Handle the error.
  14. }
  15. }
  16. else if (editingStyle == UITableViewCellEditingStyleInsert) {
  17. // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
  18. }
  19. }

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

时间: 2024-10-12 20:00:49

IOS开发之--Core Data的使用(进阶)的相关文章

ios开发:Core Data概述

Core Data 概述 2005年的四月份,Apple 发布了 OS X 10.4,在这个版本中 Core Data 框架发布了.Core Data本身既不是数据库也不是数据库访问框架.相反,Core Data是一个完整的数据模型解决方案.可以简单理解为对持久层的封装,使得我们可以通过可视化建立数据模型,简化数据存取.即使不懂SQL语句,也依然可以使用Core Data.因为Core Data将底层的数据库SQL语句封装成了一套API,并可通过可视化操作来建立数据库的模型和表之间的关系,它甚至

IOS开发之--Core Data的使用

Core Data基础知识 官方的说法是:Core Data is a schema-driven object graph management and persistence framework. 翻译过来的意思大概是:Core Data是一个模式驱动的对象图管理和持久化框架. 好吧,上面的字面意思不是很容易理解,那么我们从以下几个方面来帮助那些有其余开发经验的程序员树立一些观念: Core Data不是一个数据库,但是他可能使用一个数据库.默认情况下,Core Data将使用SQLite,

iOS教程:Core Data数据持久性存储基础教程

其实最近更多的是在写这篇文章<iOS教程:使用持久性数据Core Data>,这篇是<iOS开发教程:Storyboard全解析-第一部分>这篇的后续,但是目前还没有完成,先放出一个持久性数据存储的教程以供参考.这其实是一篇翻译文章,英文的原文见这里.我翻译的过程中改变了一些内容以便适应我们中国人的口味,下面请看教程: 就像我一直说的,Core Data是iOS编程,乃至Mac编程中使用持久性数据存储的最佳方式,本质上来说,Core Data使用的就是SQLite,但是通过一系列特

OC开发_Storyboard——Core Data

一 .NSManagedObjectContext 1.我们要想操作Core Data,首先需要一个NSManagedObjectContext2.那我们如何获得Context呢:创建一个UIManagedDocument 二.UIManagedDocument 1.UIManagedDocument是一系列用于管理存储的机制:  [将Core Data数据库放入某存储空间,相当于是管理core data 数据库的存储,所以我们只需要打开和存储]2.那我们如何得到UIManagedDocumen

zz 说说iOS的多线程Core Data

Core Data是iOS中很重要的一个部分,可以理解为基于SQLite(当然也可以是其他的Storage,如In-memory,只是SQLite比较常见)的一个ORM实现,所以有关系数据库的特性,又不用写SQL.顺便吐一下槽,官方说法是使用Core Data能减少50%-70%的代码量,但相信用过的人应该都心里明白,Core Data使用起来还是比较麻烦的,这也是为什么有不少的第三方类库来代替/二次包装Core Data. 稍微复杂的应用就有可能出现同时处理多份数据的情况,这就需要用到多线程C

iOS开发笔记--Core Bluetooth开发

推荐阅读文章:http://blog.csdn.net/pony_maggie/article/details/26740237 一.前言 CoreBluetooth框架的核心其实是两个东西,peripheral和central, 可以理解成外设和中心.对应他们分别有一组相关的API和类,如下图所示: 二.Core Bluetooth 的基本常识:1. 每个蓝牙设备都是通过服务和特征来展示自己 一个设备必然包含一个或多给服务,每个服务下面又包含多个特征2.特征是与外界交互的最小单位 比如说,一台

iOS教程:如何使用Core Data – 预加载和引入数据

这是接着上一次<iOS教程:Core Data数据持久性存储基础教程>的后续教程,程序也会使用上一次制作完成的. 再上一个教程中,我们只做了一个数据模型,之后我们使用这个数据模型中的数据创建了一个表视图,我们还学习了如何测试数据模型的可行性,今天,我们来看看如何在应用启动的时候,将已经存在的数据载入或者引用到我们的程序中去. 请注意我们在上一次的教程中学习到的是直接通过操作SQLite数据库来加载数据,你当然可以一直使用这种方法,但是这个教程教授的方法更加优雅,更加合理. 在下一部分的教程中,

Core Data 使用

简单的介绍一下 ios 数据持久化  Core Data 使用 话不多说,直接上图 接下来,在工程中 command+N 新建Core Data 文件 创建成功后,接下编辑Core Data 文件 接下来,给实体添加属性 依照添加的属性来生成相应的Model User 实体打上勾下一步 工程会自动生成 User 的Model #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> @interface User

ios开发中的4种数据持久化方式【二、数据库 SQLite3、Core Data 的运用】

               在上文,我们介绍了ios开发中的其中2种数据持久化方式:属性列表.归档解档.本节将继续介绍另外2种iOS持久化数据的方法:数据库 SQLite3.Core Data 的运用: 在本节,将通过对4个文本框内容的创建.修改,退出后台,再重新回到后台,来认识这两种持久化数据的方式.效果图如下[图1]: [图1 GUI界面效果图] [本次开发环境: Xcode:7.2     iOS Simulator:iphone6S plus   By:啊左]     一.数据库SQL