TMSEntityDataSource 0.5.1

TMSEntityDataSource 0.5.1

Mike Swan' --description='DevBot'维护。



TMSEntityDatasource

TMSEntityDatasource是一组类,旨在使用Core Data实体填充表、集合和选择器视图更加容易。

CI Status Version License Platform readme Score

示例

要运行示例项目,先克隆仓库,然后从示例目录中运行 pod install,然后点击构建和运行。

示例应用程序概述

示例应用程序允许您创建、编辑和删除具有名称、日期和类别的活动,以及为这些活动创建和编辑类别。

应用程序中有两个标签页;一个用于活动,一个用于类别。活动在表格视图中列出,类别在集合视图中。

活动详细页面包括一个包含所有类别的选择器视图,而类别详细视图有一个表格视图,它会过滤显示所选类别的活动。(在生产应用程序中,最好只使用所选类别中的 events 属性,但示例应用程序的目的是展示 TMSEntityDatasource 的各种使用模式。)

兴趣领域

在单元格组中

有两个自定义单元格类分别用于事件和类别,负责显示它们所给出的事件或类别(注意输出接口都是私有的,消除了从单元格外部设置它们的诱惑)。

在这些类中,主要查看entity属性和event/category属性,因为这些显示了如何触发设置视图以及从通用的NSManagedObject(即entity)转换为单元格所处理的特定实体的一种方法。

在视图控制器组中

EventsTableViewController.swift

要查看在视图加载时如何设置表格视图的数据源,请查看setupDataSource()

要向上下文中添加新的实体,请查看addEvent(_:)。这个版本对新创建的事件进行了更改,类别视图显示忽略返回的实体。

CategoryCollectionViewController.swift

要查看在视图加载时如何设置集合视图的数据源,请查看setupDataSource()

要向上下文中添加新实体,请检查 addEvent(_:)。由于 addItem() 被标记为 @discardableResult,如果您在创建时不希望进行任何更改,可以直接忽略返回的实体。

EventDetailViewController.swift

setupDatasource() 展示了配置 EntityPickerDataSource。在此示例中,我们由于类别关系是可选的,所以在拾取器的顶部包含了一个空白选项。

由于没有简单的方法来告诉 EntityPickerDataSource 我们希望在拾取器视图中显示哪些类别实体的属性,因此客户端应用程序保留委托方法。但 EntityPickerDataSource 提供了一些有用的方法来帮助…

configureView() 展示在配置完数据源后拾取视图的初始设置。它从数据源获取活动类别的行索引。

pickerView(_:, titleForRow:, forComponent: ) 展示了通过使用 EntityPickerDataSourceentity(atRow:) 方法,如何轻松地获取用于每行的正确字符串。pickerView(_:, didSelectRow:, inComponent: ) 在将所选类别分配给活动时使用同一方法。

CategoryDetailViewController.swift

在这个示例中,setupDataSource() 展示了使用谓词设置数据源。

要求

  • iOS 11.0 或更高版本
  • Core Data

安装

可以通过 CocoaPods 获取 TMSEntityDataSource。要安装它,只需将以下行添加到您的 Podfile 中:

pod 'TMSEntityDataSource'

如果您不想使用 CocoaPods,只需将您需要的任何视图的文件拖到项目中。

用法

TMSEntityDatasource旨在使用尽可能简单。对于每个你想在视图中显示一种Core Data实体类型的数据视图,您将想要遵循一些步骤

  1. 创建一个自定义的UItableViewCellUICollectionViewCell子类,并使它遵循EntityCellProtocol
  2. 将用于保存数据源的属性添加到视图控制器中。
  3. viewDidLoad()期间设置数据源。
  4. 如有需要,添加一个@IBAction来告诉数据源创建显示实体的新实例。
  5. 对于选择视图,设置两个UIPickerViewDelegate方法。

1. 创建一个自定义的UItableViewCellUICollectionViewCell子类,并使它遵循EntityCellProtocol

EntityCellProtocol的唯一要求是一个属性

var entity: NSManagedObject? 

为了使单元格内的操作更简单,你可能希望有一种将entity转换为单元格显示的特定子类NSManagedObject的方法...

private var myEntity: MyEntity? {
	get {
		guard let myEntity = entity as? MyEntity else { return nil }
		return myEntity
	}
}

剩下的事情就是根据传入的实体配置单元格。一个didSet观察者对触发此类配置非常有用

var entity: NSManagedObject? {
	didSet {
		configureCell()
	}
}

2. 在视图控制器中添加一个用于保存数据源的属性。

private var dataSource: EntityTableDataSource<MyEntity>?

MyEntity当然是你想在表格中显示的任何Core Data实体。

3. 在viewDidLoad()期间设置数据源。

要设置数据源,请确保您有一个管理对象上下文和一个需要数据源视图。然后您可以创建一个谓词(如果需要),创建数据源,并设置(如必要)任何排序描述符。一旦处理完这些,就启动获取请求。

private func setupDataSource() {
	guard let moc = managedObjectContext, let collectionView = self.collectionView else { return }
	dataSource = EntityCollectionDataSource<MyEntity>(collectionView: collectionView, reuseIdentifier: reuseIdentifier, context: moc, predicate: nil)
	dataSource?.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
	dataSource?.initiateFetchRequest()
}

在创建选择视图数据源时,有一个额外的可选参数,允许您指定在选择的开始处添加空行。

dataSource = EntityPickerDataSource<MyEntity>(pickerView: picker, context: moc, predicate: nil, includeBlankOption: true)

包括空行时,数据源会为您计算行索引,您只需记住索引0表示空值。

4. 如果需要,添加一个 @IBAction 来告诉数据源创建所显示实体的新实例。

所有数据源都有一个方便的 addItem() 方法,该方法创建数据源正在处理实体的新实例并将其插入到托管对象上下文中。它返回这个新实例,以便您可以进行任何初始调整

@IBAction func addAnEntity(_ sender: Any) {
	let theEntity = dataSource?.addItem()
	theEntity?.name = "Awesome!"
}

如果您只想在上下文中创建实体,则可以忽略返回的实体

@IBAction func addAnEntity(_ sender: Any) {
	dataSource?.addItem()
}

5. 对于选择视图,设置两个 UIPickerViewDelegate 方法。

由于选择视图没有单元格,代理必须为每一行提供一个字符串。尽管如此,选择数据源通过提供了针对特定行索引的正确实体的方法,使这个过程变得相当简单。它甚至考虑了选择器开头是否存在空白选项。

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
	if row == 0 { return " " }
	return dataSource?.entity(atRow: row)?.name ?? " "
}

您可以将该方法的第第一行作为 entity(atRow: ),如果存在空白行,将为行 0 返回 nil(0 - 1 = -1,超出所有数组范围)。

当用户从选择器中选择项时,您也使用相同的方法来确定应该将哪个实体放置到关系中。

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
	guard row != 0 else {
		currentEntity?.category = nil
		return
	}
	currentEntity?.category = dataSource?.entity(atRow: row)
}

贡献

如果您看到 TMSEntityDataSource 可以改进或需要修复的方式,请随时给我发一个拉取请求,或者至少打开一个问题。即使您认为您的更改很小,也要发送它,它可能对某个人来说意义重大。

目前需要帮助的主要区域是错误处理,目前错误信息仅被记录下来,这不是最佳选择。

作者

theMikeSwan, [email protected]

许可协议

TMSEntityDataSource 在 MIT 许可协议下可用。有关更多信息,请参阅 LICENSE 文件。