65.9K
CodeProject 正在变化。 阅读更多。
Home

iOS 设备上 Core Data 概览

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (5投票s)

2011 年 8 月 9 日

CPOL

12分钟阅读

viewsIcon

26526

《Core Data for iOS: Developing Data-Driven Applications for the iPad, iPhone, and iPod touch》一书的章节摘录

ShowCover.jpg

Tim Isted, Tom Harrington
由 Addison-Wesley Professional 出版
ISBN-10: 0-321-67042-6
ISBN-13: 978-0-321-67042-7

本章内容

  • 简史
  • 为何在 iOS 上使用 Core Data?
  • Core Data 在 iOS 和桌面端的区别
  • Core Data 案例研究

Mac OS X 10.4 Tiger 引入了 Core Data,旨在为应用程序的模型数据提供统一的存储和获取框架。在 Mac OS X 10.5 Leopard 中得到进一步增强后,Apple 随后在 iPhone OS 3.0 及以上版本中将其引入 iOS 设备。Core Data 框架无疑大大减轻了处理模型数据的繁琐工作,但其学习曲线也相当陡峭。

本概述首先简要回顾 Core Data 的发展历史,然后对其框架进行高层次的概述。本章的最后部分将探讨 iOS 开发者如何利用 Core Data 的强大功能来简化其应用程序中的模型处理的真实世界案例。

简史

如今被称为 Core Data 的大部分功能,最初是企业对象框架 (EOF)。EOF 由 NeXT 创建,作为 WebObjects 的一部分,用于访问关系数据库系统中保存的数据。为了让开发者不必编写大量底层数据库访问代码,EOF 提供了一种机制,通过对象关系映射将数据作为面向对象的类结构来访问。

对象关系映射不是编写代码与数据库交互并要求它返回数据库表和列的行,而是将这些表“映射”到类,将列映射到类属性,将行映射到类实例。这样,即使更改类下方的底层数据库或存储机制,也不必担心更改访问这些类的任何代码,因为 EOF 会在后台处理所有事情。

Core Data 的诞生

Core Data 的许多功能后来“源自”EOF,但重要的是要强调,Core Data 本身既不是数据库,也不是数据库访问框架。相反,Core Data 是一个完整的数据模型解决方案,它允许对对象图进行可视化设计,提供用于创建查询对象图中的对象的代码,以及用于将对象持久化到磁盘的代码。

虽然通常使用 Core Data 将对象存储在 SQL 数据库(精确地说是 SQLite)中,但同样可以不使用数据库存储,例如 XML 文件、二进制文件,甚至完全由开发者根据特定需求创建的自定义持久化存储。在桌面上,Apple 提供 SQLite、XML 和二进制存储选项。在 iOS 上,没有 XML 存储,大多数 iOS 应用程序最终都使用 SQLite 存储。

同样重要的是要强调,由 Core Data 支持的模型可以用于存储各种类型的数据。它不一定必须是传统意义上的数据库类数据,例如医生诊所的病人记录,或公司会计应用程序的发票和财务信息。

使用 Core Data 存储 iOS 绘图应用程序的矢量图形信息、社交网络应用程序的账户信息和搜索词,或者游戏的高分和持久状态信息,同样简单。

为何在 iOS 上使用 Core Data?

Core Data 框架提供了一种经过验证、非常快速的数据模型访问方式。它在内存或处理器使用方面成本不高,并且捆绑了许多我们免费获得的非常有用的功能。

关系管理

由于其作为关系数据库系统辅助工具的渊源,Core Data 的主要卖点之一是它能够管理其维护的对象之间的关系,例如手术室中属于医生的病人。使用可视化数据模型设计器,您可以使用一对一一对多多对多等术语来定义对象之间的链接。该框架设计为尽可能使用双向关系,因此维护数据之间的“参照完整性”非常容易。

您定义的关系甚至可以设置规则,例如要求某个特定关系始终被定义(例如,一笔财务交易必须与银行账户相关联),或者指定一家公司必须至少有一名董事。在将新对象保存或持久化到底层存储时,框架将拒绝接受不遵守所需规则的对象,从而维护对象图的完整性

同样,如果您更改了关系的一端,Core Data 会自动处理另一端的相应更改。例如,如果您将一名患者从一个医生转移到另一个医生,每个医生的相关患者列表都会自动相应更新。同样,如果您从财务应用程序中删除了一个银行账户,所有相关的交易也会自动删除,前提是关系规则已在数据模型中正确设置。

托管对象和数据验证

当您处理由 Core Data 存储支持的对象时,您处理的是所谓的托管对象。标准的托管对象功能包含前面提到的部分关系处理,但也支持数据验证

对象的验证发生在对象的属性(或属性)上。您可以在模型本身中设置每个属性的规则,例如

  • 一个人的工资不能低于零

或者使用自定义验证规则来强制执行多个属性之间的规则,例如

  • 如果一个病人年龄小于某个阈值,则不能有孩子。

如前所述,如果您尝试使用不通过验证测试的值更新对象,Core Data 将会报错并阻止您保存不正确的数据。

撤销和状态管理

如果需要,Core Data 还会自动维护一个撤销堆栈,这意味着即使在对象已保存到持久化存储后,也可以撤销对对象的更改。同样,这是自动为您处理的,因此您不必担心自己编写撤销管理代码。

因此,使用 Core Data 的理由非常充分。而且,由于桌面和 iOS 平台使用完全相同的底层框架代码,一旦您学会了它在 iOS 上的工作原理,您就已经对它在桌面上的工作原理有了很多了解!尽管如此,在 iOS 上使用 Core Data 与在 Mac 桌面上的实践中确实存在一些差异。

Core Data 在 iOS 和桌面端的区别

桌面和 iOS Core Data 支持之间的一个主要区别是,目前 iOS 上不支持绑定。在桌面上,绑定使用键值观察 (KVO) 和键值编码 (KVC) 来维护用户界面项与模型对象或属性之间的链接。通过绑定,您可以在不编写任何代码的情况下构建出色的桌面 Core Data 应用程序——您只需使用 Xcode 4 的 Interface Editor(Xcode 3 下的独立 Interface Builder 应用程序)将表视图和文本字段等界面项绑定到由对象和数组控制器从 Core Data 存储自动获取的托管对象组。

在 iOS 上,这种即时满足的“带绑定 Core Data”式开发是不可能的;相反,您需要直接与 Core Data 框架的各个部分进行交互,为您的用户界面提供相关信息。

已获取结果控制器

为了协助这一过程,Apple 提供了一个 Core Data 新增的、iOS 特有的类,名为 NSFetchedResultsController。顾名思义,NSFetchedResultsController(它有一个专门的章节进行介绍,即第 5 章)用作控制器层类,帮助视图与从持久化存储获取的数据进行交互。它主要设计用作 UITableView 的数据源,控制视图应显示的行数和节数,并提供每行的内容。

已获取结果控制器以最高效的方式工作,以消除一次性将所有已获取对象加载到内存的需求,并自动处理当前未被访问的对象。这使得处理大量对象更加容易。

例如,如果您使用已获取结果控制器在一个表视图中显示数千个对象的集合,在任何给定时间,都只会将其中少数对象加载到内存中。

Core Data 案例研究

MoneyWell for iPhone

MoneyWell 是一款个人理财应用程序,旨在使跟踪支出和管理现金流的过程变得显而易见。它以屏幕上的“收支桶”形式使用信封预算方法来容纳交易,让用户通过准确地了解每个收入或支出类别中的可用金额来主动管理可用现金。

在设计 MoneyWell 时,Mac OS X Tiger 和 Core Data 都还是崭新的。MoneyWell 中的数据关系相当复杂,但 Core Data 简化了模式设计和开发过程。当 Apple 发布 iPhone SDK 时,很明显 MoneyWell 将成为一款非常适合随身携带的应用程序。问题是,Core Data 在第一个版本中并未向开发者提供。我们实际上推迟了 MoneyWell for iPhone 的开发,假设 Apple 会将其 Core Data 迁移到其设备平台。事实证明这是一个明智的决定,因为 Apple 在 3.0 SDK 中确实包含了 Core Data。

这解决了许多开发问题。在 MoneyWell for iPhone 中创建模型层只需将 Xcode 数据模型复制到新项目中。此外,Mac 和 iOS 版的 MoneyWell 共享相同的数据文件,使我们能够使用所有现有的测试文档。我们还受益于 Core Data 是一个一流的框架,已针对 iOS 平台上的性能进行了大量优化。数据访问、数据持久化和对象图操作等工作在整个开发过程中都非常简单,使我们能够专注于解决更重要的问题,例如创建良好的用户体验。一个特别大的收获是 Core Data 与 UITableView 的结合使用。正如您可能想象的那样,一个典型用户可能拥有多年的财务数据,这很容易耗尽移动设备的内存空间。没有 Core Data,我们将被迫编写复杂的分页算法或广泛的 SQLite 查询,但相反,我们可以查询一组交易,并依赖 Core Data 智能地将数据分页进出内存。

使用 Core Data 轻松为我们节省了五个月或更长的开发时间。

Kevin Hoctor 和 Michael Fey, No Thirst Software LLC

Calcuccino

Calcuccino 是一款程序员计算器,它利用 iPhone 的菜单和滑动手势来改进传统的计算器。其结果是一款适用于编程、工程和科学用途的强大计算器,具有大按钮,可实现快速可靠的输入。

为 Calcuccino 选择使用 Core Data 并非显而易见。Calcuccino 没有大量的数据处理需求,但它需要存储用户计算的合理历史记录,以便他们以后可以查看或重用之前的结果。Calcuccino 还需要保存当前计算的状态信息,以便用户在切换应用程序并稍后返回时可以恢复。在 Core Data 之前,这两种需求都将通过 XML 文件来持久化信息,但这会导致编写大量代码来处理 XML 本身。

Core Data 在 Xcode 中提供了一个数据模型设计器,因此我们用它来绘制数据结构——主要是 HistoryStep 实体的历史步骤存储,以及 OpStep 实体的当前计算状态。对于计算引擎本身,我们定义了一个 CalcValue 类——这是 Calcuccino 中使用的基本数字类型(类似于 Cocoa 的 NSNumber 类,但增加了整数大小和格式)。所有 CalcValue 实例都使用 GeneralValue 实体的实例存储在 Core Data 存储中。

Calcuccino 的数据模型非常清晰,并且很好地映射到了应用程序的要求。有一个 CalcStore 类负责处理应用程序的 Objective-C 类与 Core Data 调用之间的接口。它让我失望的是,在 Objective-C 类和实体之间仍然需要映射代码,但这与打包和解包类到 XML 的代码没有什么不同。我猜想我们将进一步远离原始的 NSManagedObjects,而更多地转向自定义类以减少映射代码。此外,还需要一种思维方式的转变,在 Cocoa 的常规容器类(NSArrayNSDictionary)和使用谓词和获取请求访问实体之间进行切换。

鉴于我们现在使用 Core Data 的经验,问题将是“我们会再次使用 Core Data 吗?”

答案是,这证实了我们相信我们做出了正确的决定。UITableView 和 Core Data 与 NSFetchedResultsController 之间的接口配合起来非常愉快,特别是使用属性自动按天分组历史视图中的计算。一旦我们为 Calcuccino 积累了更多的版本,并且我们不得不使用 Core Data 的版本控制功能来版本控制数据库,我们希望我们将继续相信我们做出了正确的决定!

Andy Dean, Cambridge Coders Ltd

美联社

当我开始开发美联社移动应用程序时,我就知道它必须是一个 Core Data 应用程序。我们处理的数据量太大,无法尝试使用任何其他类型的持久化层。此外,基于我们对异步数据传输的要求,Core Data 是一个显而易见的选择。

能够设置直接馈入 Core Data 模型的数据解析器,并且可以在后台线程中保存,这对于提高应用程序的性能非常有帮助。

在设计应用程序时,我们知道与服务器的接口将用于多个应用程序,因此我们将其设计为一个单独的库。通过将该库设计为“仅仅”向 Core Data 持久化存储添加数据,我们能够为构建在其之上的任何应用程序提供一个通用、易于理解的接口。每个应用程序只需监视 Core Data 中的更改,即可知道底层数据已更改。通过这样做,我们将应用程序和库之间的接口代码降到了最低。

我们现在使用这种库设计已经一年多了,几乎没有出现任何问题。该库到目前为止已被数十个应用程序使用,并且性能非常好。如果使用了其他持久化引擎,我怀疑我们仍然会与性能问题和内存问题作斗争。

Marcus S. Zarra,Zarra Studios LLC

© . All rights reserved.