Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. CloudKit

使用CloudKit构建购物清单应用程序:添加关系

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Building a Shopping List Application With CloudKit.
Building a Shopping List Application With CloudKit: Adding Records
Building a Shopping List Application With CloudKit: Sharing Shopping Items

Chinese (Simplified) (中文(简体)) translation by Soleil (you can also view the original English article)

本系列的上一个教程中,我们添加了添加,更新和删除购物清单的功能。 但是,没有任何项目的购物清单并不是很有用。 在本教程中,我们将添加添加,更新和删除购物清单中的项目的功能。 这意味着我们将使用引用和CKReference类。

我们还将仔细研究购物清单应用程序的数据模型。 如何轻松地更改数据模型以及应用程序如何响应我们在CloudKit仪表板中所做的更改?

先决条件

请记住,我将使用Xcode 7Swift 2.如果您使用的是旧版本的Xcode,请记住您使用的是不同版本的Swift编程语言。

在本教程中,我们将继续在本系列的第二篇教程中停止。 您可以从GitHub下载或克隆项目。

1.购物清单详情

目前,用户可以通过点击详细信息披露指示符来修改购物清单的名称,但是用户还应该能够通过在列表视图控制器中点击一个来查看购物清单的内容。 为了使这项工作,我们首先需要一个新的UIViewController子类。

第1步:创建ListViewController

ListViewController类将在表视图中显示购物清单的内容。 ListViewController类的接口看起来类似于ListsViewController类的接口。 我们导入CloudKitSVProgressHUD框架,并使该类符合UITableViewDataSourceUITableViewDelegate协议。 因为我们将使用表视图,所以我们声明一个常量ItemCell,它将用作单元重用标识符。

我们声明了三个出口,类型为UILabelmessageLabel!,UITableView类型的tableView,以及UIActivityIndicatorView类型的activityIndicatorView。 列表视图控制器保持对它在list属性中显示的购物清单的引用,该属性的类型为CKRecord!。 购物清单中的商品存储在items属性中,该属性的类型为[CKRecord]。 最后,我们使用辅助变量selection来跟踪用户选择的购物清单中的哪个项目。 这将在本教程后面变得清晰。

第2步:创建用户界面

打开Main.storyboard,添加一个视图控制器,并在Identity Inspector中将其类设置为ListViewController。 选择列表视图控制器的原型单元格,按下控制键,然后从原型单元格拖动到列表视图控制器。 从弹出的菜单中选择“Show”,并在 Attributes Inspector中将标识符设置为“List ”。

将表视图,标签和活动指示器视图添加到视图控制器的视图中。 不要忘记连接视图控制器的出口以及表格视图的出口。

选择表视图并在Attributes Inspector中将Prototype Cells设置为1。 选择原型单元格,将Style设置为Right Detail,将Identifier设置为ItemCell,将Accessory设置为Disclosure Indicator。 这就是视图控制器在完成时的样子。

List View Controller

第3步:配置View Controller

在我们重新访问CloudKit框架之前,我们需要为它将要接收的数据准备视图控制器。 首先更新viewDidLoad的实现。 我们将视图控制器的标题设置为购物清单的名称,并调用两个辅助方法setupViewfetchItems

setupView方法与我们在ListsViewController类中实现的方法相同。

虽然我们正在使用它,但我们还要实现另一个熟悉的帮助方法updateView。 在updateView中,我们根据items属性中存储的项更新视图控制器的用户界面。

我现在要把fetchItems留空。 完成列表视图控制器的设置后,我们将重新访问此方法。

第4步:表视图数据源方法

我们几乎已准备好将该应用程序用于另一次测试运行。 在我们开始之前,我们需要实现UITableViewDataSource协议。 如果您已阅读本系列的前几部分,那么实现将看起来很熟悉。

第5步:处理选择

为了将所有内容组合在一起,我们需要重新访问ListsViewController类。 首先实现UITableViewDelegate协议的tableView(_:didSelectRowAtIndexPath :)方法。

我们还需要更新prepareForSegue(segue:sender :)以处理我们刚刚创建的segue。 这意味着我们需要在switch语句中添加一个新case 

为了满足编译器,我们还需要在ListsViewController.swift的顶部声明SegueList常量。

构建并运行应用程序以查看是否所有内容都已正确连接。 因为我们还没有实现fetchItems方法,所以不会显示任何项目。 这是我们需要解决的问题。

2.获取物品

第1步:创建记录类型

在我们从CloudKit后端获取项目之前,我们需要在CloudKit仪表板中创建一个新的记录类型。 导航到CloudKit仪表板,创建新记录类型,并将其命名为Items。 每个项目都应该有一个名称,因此创建一个新字段,将字段名称设置为name并将字段类型设置为String

每个项目还应该知道它属于哪个购物清单。 这意味着每个项目都需要对其购物清单的引用。 创建一个新字段,将字段名称设置为list并将字段类型设置为ReferenceReference字段类型是为了这个目的而设计的,用于管理关系。

Item Record Type

返回Xcode,打开ListsViewController.swift,并在Items记录类型的顶部声明一个新常量。

第2步:获取项目

打开ListViewController.swift并导航到fetchItems方法。 该实现类似于ListsViewController类的fetchLists方法。 但是有一个重要的区别。

fetchItemsfetchLists之间的区别是我们传递给CKQuery初始化程序的谓词。 我们对用户私有数据库中的每个项目都不感兴趣。 我们只对与特定购物清单相关联的商品感兴趣。 这反映在CKQuery实例的谓词中。

我们通过传入一个CKReference实例来创建谓词,我们通过调用init(recordID:action :)来创建它。 此方法接受两个参数,一个引用购物清单记录的CKRecordID实例和一个确定删除购物清单时发生的情况的CKReferenceAction实例。

参考操作与核心数据中的删除规则非常相似。 如果引用的对象(此示例中的购物清单)被删除,则CloudKit框架会检查引用操作,以确定对包含已删除记录的引用的记录应该发生什么。 CKReferenceAction枚举有两个成员值:

  • None:如果删除引用,则引用已删除记录的记录不会发生任何变化。
  • DeleteSelf:如果删除引用,则还会删除引用已删除记录的每条记录。

因为没有购物清单就不存在任何项目,我们将引用操作设置为DeleteSelf

processResponseForQuery(records:error :)方法不包含任何新内容。 我们处理查询的响应并相应地更新用户界面。

构建并运行应用程序。 您将看不到任何项目,但用户界面应更新反映购物清单为空。

3.添加项目

第1步:创建AddItemViewControler

是时候实现将商品添加到购物清单的功能了。 首先创建一个新的UIViewController子类AddItemViewController。 视图控制器的接口类似于AddListViewController类的接口。

在顶部,我们导入CloudKitSVProgressHUD框架。 我们声明AddItemViewControllerDelegate协议,它将与AddListViewControllerDelegate协议起到相同的作用。 该协议定义了两种方法,一种用于添加项目,另一种用于更新项目。

我们声明了两个出口,一个文本字段和一个条形按钮项。 我们还为委托声明了一个属性和一个辅助变量newItem,它帮助我们确定是创建新项目还是更新现有项目。 最后,我们声明一个属性list ,用于引用要添加项目的购物清单以及我们正在创建或更新的项目的属性item

在我们创建用户界面之前,让我们在storyboard中实现两个我们需要的操作,cancel(_:)save(_ :)。 我们将在本教程后面更新save(_ :)动作的实现。

第2步:创建用户界面

打开Main.storyboard,将一个条形按钮项添加到列表视图控制器的导航栏,并在Attributes Inspector中将System Item设置为Add。 从Object Library中拖动视图控制器并将其类设置为AddItemViewController。 从我们刚创建的条形按钮项创建一个segue到添加项视图控制器。 从弹出的菜单中选择Show,并将segue的标识符设置为ItemDetail

将两个条形按钮项添加到添加项视图控制器的导航栏,左侧的取消按钮和右侧的保存按钮。 将每个栏按钮项连接到相应的操作。 将文本字段添加到视图控制器的视图中,不要忘记连接视图控制器的插座。 这是添加项目视图控制器在完成后应该是什么样子。

Add Item View Controller

第3步:配置View Controller

添加项视图控制器的实现不包含我们尚未涉及的任何内容。 但是有一个例外,我们将在稍后讨论。 我们首先在viewDidLoad中配置视图控制器。

我们调用setupView,一个帮助方法,并更新newItem的值。 如果item属性等于nil,则newItem等于true。 这有助于我们确定是否正在创建或更新购物清单项目。

我们还将视图控制器添加为UITextFieldTextDidChangeNotification类型的通知的观察者。 这意味着当nameTextField的内容发生更改时,将通知视图控制器。

viewDidAppear(animated:)中,我们通过在nameTextField上调用becomeFirstResponder来显示键盘。

setupView方法调用两个辅助方法updateNameTextFieldupdateSaveButton。 这些辅助方法的实现很简单。 在updateNameTextField中,我们填充文本字段。 在updateSaveButton中,我们根据文本字段的内容启用或禁用保存按钮。

在我们看一下save(_:)方法的更新实现之前,我们需要实现textFieldDidChange(_:)方法。 我们所做的只是调用updateSaveButton来启用或禁用保存按钮。

第4步:保存项目

save(_:)方法是AddItemViewController类最有趣的方法,因为它向我们展示了如何使用CloudKit引用。 看一下下面的save(_:)方法的实现。

由于我们在AddListViewController类中保存了记录,因此大部分实现应该看起来很熟悉。 我们最感兴趣的是该项目如何保持对其购物清单的引用。 我们首先通过调用指定的初始化器init(recordID:action:)来创建一个CKReference实例。 几分钟前,当我们创建用于获取购物清单项目的查询时,我们详细介绍了创建CKReference实例的细节。

告诉关于此参考的项目很容易。 我们在item属性上调用setObjec(_:forKey:),将CKReference实例作为值传递,并将"list"作为键传递。 密钥对应于我们在CloudKit仪表板中分配的字段名称。 将项目保存到iCloud与我们之前介绍的相同。 这就是使用CloudKit引用是多么容易。

processResponse(record:error:)的实现不包含任何新内容。 我们检查是否弹出了任何错误,如果没有抛出错误,我们会通知代表。

第5步:更新ListViewController

我们在ListViewController类中还有一些工作要做。 首先使ListViewController类符合AddItemViewControllerDelegate协议。 这也是为具有标识符ItemDetail的segue声明常量的好时机。

实现AddItemViewControllerDelegate协议是微不足道的。 在controller(_:didAddItem :)中,我们将新项添加到items,排序items,重新加载表视图和调用updateView

controller(_:didUpdateItem:)的实现更加容易。 我们对items进行排序并重新加载表视图。

sortItems中,我们使用sortInPlace函数(一种MutableCollectionType协议的方法)按名称对CKRecord实例数组进行排序。

我们需要实现,更新和删除购物清单项目的另外两个功能。

第6步:删除项目

要删除项目,我们需要实现UITableViewDataSource协议的tableView(_:commitEditingStyle:forRowAtIndexPath:)。 我们获取需要删除的购物清单项并将其传递给deleteRecord(_:)方法。

deleteRecord(_:)的实现不包含任何新内容。 我们在私有数据库上调用deleteRecordWithID(_:completionHandler:)并在完成处理程序中处理响应。

processResponseForDeleteRequest(record:recordID:error:)中,我们更新items属性和用户界面。 如果出现问题,我们会通过显示提醒来通知用户。

第7步:更新项目

用户可以通过点击详细信息披露指示符来更新项目。 这意味着我们需要实现tableView(_:accessoryButtonTappedForRowWithIndexPath :)委托方法。 在此方法中,我们存储用户的选择并手动执行ListDetail segue。 请注意,tableView(_:didSelectRowAtIndexPath:)方法没有任何反应。 我们所做的就是取消选择用户点击的行。

prepareForSegue(_:sender:)中,我们使用selection属性的值获取购物清单项,并配置目标视图控制器,AddItemViewController类的一个实例。

这就是我们删除和更新购物清单项目所需要做的全部工作。 在下一节中,我们将探讨在CloudKit仪表板中更新数据模型是多么容易。

4.更新数据模型

如果您曾经使用过Core Data,那么您应该谨慎地更新数据模型。 您需要确保不破坏任何内容或破坏任何应用程序的持久存储。 CloudKit更灵活一点。

Items记录类型当前有两个字段,名称和列表。 我想通过添加一个新字段来向您展示更新数据模型所涉及的内容。 打开CloudKit仪表板并向Items记录添加新字段。 将字段名称设置为number并将字段类型设置为Int(64)。 不要忘记保存更改。

Update Item Record Type

现在让我们添加修改项目编号的功能。 打开AddItemViewController.swift并声明两个出口,一个标签和一个步进器。

我们还需要添加在步进器值更改时触发的操作。 在numberDidChange(_:)中,我们更新numberLabel的内容。

打开Main.storyboard并向添加项视图控制器添加标签和步进器。 将视图控制器的出口连接到相应的用户界面元素,并将numberDidChange(_:)操作连接到Value Changed事件的步进器。

Update Add Item View Controller

AddItemViewController类的save(_:)动作也略有变化。 让我们看看它是什么样的。

我们只需要添加两行代码。 在顶部,我们将步进器的值存储在一个常量number中。 当我们配置item时,我们将number设置为“number”键的值,这就是它的全部内容。

我们还需要实现一个帮助方法来更新添加项视图控制器的用户界面。 updateNumberStepper方法检查记录是否有一个名为number的字段,如果有,则更新步进器。

我们在AddItemViewController类的setupView方法中调用updateNumberStepper

为了可视化每个项目的数量,我们需要对ListViewController进行一次更改。 在tableView(_:cellForRowAtIndexPath:)中,我们将单元格右侧标签的内容设置为项目编号字段的值。

这就是我们实现对数据模型所做的更改所需要做的全部工作。 没有必要执行迁移或类似的事情。 CloudKit负责细节的细节。

结论

您现在应该拥有CloudKit框架的正确基础。 我希望您同意Apple在框架和CloudKit仪表板方面做得很好。 我们在本系列中没有涉及到很多内容,但这应该足以让您在自己的项目中开始使用CloudKit。

如果您有任何问题或意见,请随时将它们留在下面的评论中或在Twitter上与我联系。

关注我们的公众号
Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.