GenericDataSources 3.1.1

GenericDataSources 3.1.1

测试已测试
语种语言 SwiftSwift
许可证 MIT
发布最后发布2020年3月
SPM支持 SPM

Mohamed Afifi 维护。



GenericDataSource

Swift Version

Version

Build Status Coverage Status Documentation

一个用于 Swift 编写的通用小可重用组件,为 UITableView/UICollectionView 的数据源实现。

功能

  • BasicDataSource 可以轻松地自动解包绑定模型到单元格。
  • SegmentedDataSource 可以轻松构建分段控件或用于您的 UICollectionView/UITableView 数据源的空状态。
  • CompositeDataSource 可以使用易于使用的组件构建复杂的单元格/模型结构(BasicDataSource SegmentedDataSource 或其他 CompositeDataSource)。
  • 支持 UICollectionView 补充视图、UITableView 标题视图和页脚视图。
  • 能够从 UIKit 类中覆盖任何数据源方法。
  • 全面的单元测试覆盖率。
  • 完整文档

需求

  • iOS 8.0+
  • Xcode 10
  • Swift 4.0+

安装

CocoaPods

要使用CocoaPods将GenericDataSource集成到您的Xcode项目中,请在您的Podfile中指定它

pod 'GenericDataSources'

重要提醒:Pod的名称是GenericDataSource,结尾有“s”。

Carthage

要使用Carthage将GenericDataSource集成到您的Xcode项目中,请在您的Cartfile中指定它

github "GenericDataSource/GenericDataSource"

手动操作

GenericDataSource.xcodeproj通过拖动的方式添加到您的项目文件中。

然后您可以参考将现有的框架添加到项目中


示例

基本数据源示例

UITableView

创建一个基本的数据源并将其绑定到表格视图。

let dataSource = BasicBlockDataSource<Example, BasicTableViewCell>() { (item: Example, cell: BasicTableViewCell, indexPath) -> Void in
    cell.titleLabel?.text = item.title
}

// Need to keep a strong reference to our data source.
self.dataSource = dataSource

// register the cell
tableView.ds_register(cellClass: BasicTableViewCell.self)
// bind the data source to the table view
tableView.ds_useDataSource(dataSource)

dataSource.items =  <<retrieve items>> // Can be set and altered at anytime

就是这样!您已经实现了第一个数据源。无需排队!无需转换!简单而智能。

UICollectionView

现在,让我们将这个概念提升到下一个层次。假设在实现它之后,需求发生了变化,我们需要使用 UICollectionView 来实现它。

let dataSource = BasicBlockDataSource<Example, BasicCollectionViewCell>() { (item: Example, cell: BasicCollectionViewCell, indexPath) -> Void in
    cell.titleLabel?.text = item.title
}

// Need to keep a strong reference to our data source.
self.dataSource = dataSource

// register the cell
collectionView.ds_register(cellClass: BasicCollectionViewCell.self)
// bind the data source to the collection view
collectionView.ds_useDataSource(dataSource)

dataSource.items =  <<retrieve items>> // Can be set and altered at anytime

您所需要做的,仅仅是将细胞类以及当然的表格视图改为集合视图。

实际上,这为许多可能性打开了大门。您可以继承自 BasicDataSource 并实现一个基于由细胞实现的协议的自定义通用数据源,这样您就无需重复配置部分。您将创建这样的数据源。

let dataSource1 = CustomDataSource<BasicTableViewCell>() // for table view
let dataSource2 = CustomDataSource<BasicCollectionViewCell>() // for collection view

App store Featured Example

假设我们想实现以下屏幕,App StoreFeatured标签页。

App Store Example Screenshot

如果您想查看完整的源代码,可以在Example项目下找到,即 AppStoreViewController.swift

  1. 我们将创建单元格,就像我们通常做的那样。
  2. 现在,我们需要考虑数据源。
  3. 很简单,每个细胞类型一个数据源(BasicDataSource)。
  4. 对于具有不同细胞类型的表格视图行,使用 CompositeDataSource(sectionType: .single)
  5. 使用 SegmentedDataSource 在加载视图和数据视图之间切换。
  6. SegmentedDataSource 数据源绑定到表格视图,这样就完成了。
  7. 看我们是如何从结构上思考我们的UI和数据源,而不是一个大的单元格。

我们还没有讨论到特色部分单元格的 UICollectionView。它非常简单,就是 BasicDataSource

看我们如何在以下代码中实现屏幕

  1. 创建单元格。
class AppStoreFeaturedSectionTableViewCell: UITableViewCell { ... }
class AppStoreQuickLinkLabelTableViewCell: UITableViewCell { ... }
class AppStoreQuickLinkTableViewCell: UITableViewCell { ... }
class AppStoreFooterTableViewCell: UITableViewCell { ... }
class AppStoreLoadingTableViewCell: UITableViewCell { ... }
  1. 创建 BasicDataSource
class AppStoreLoadingDataSource: BasicDataSource<Void, AppStoreLoadingTableViewCell> {
    // loading should take full screen size.
    override func ds_collectionView(_ collectionView: GeneralCollectionView, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return collectionView.size
    }
}
class AppStoreFooterDataSource: BasicDataSource<Void, AppStoreFooterTableViewCell> { ... }
class AppStoreQuickLinkDataSource: BasicDataSource<FeaturedQuickLink, AppStoreQuickLinkTableViewCell> { ...  }
class AppStoreFeaturedAppsDataSource: BasicDataSource<FeaturedApp, AppStoreFeaturedAppCollectionViewCell> { ... }
class AppStoreFeaturedAppsSectionDataSource: BasicDataSource<FeaturedSection, AppStoreFeaturedSectionTableViewCell> { ... }
class AppStoreQuickLinkLabelDataSource: BasicDataSource<String, AppStoreQuickLinkLabelTableViewCell> { ... }
  1. 创建包含特色页面的 CompositeDataSource
class AppStoreFeaturedPageDataSource: CompositeDataSource {
    init() { super.init(sectionType: .single)] }

    var page: FeaturedPage? {
        didSet {
            // remove all existing data sources
            removeAllDataSources()

            guard let page = page else {
                return
            }

            // add featured apps
            let featuredApps = AppStoreFeaturedAppsSectionDataSource()
            featuredApps.setSelectionHandler(UnselectableSelectionHandler())
            featuredApps.items = page.sections
            add(featuredApps)

            // add quick link label
            let quickLinkLabel = AppStoreQuickLinkLabelDataSource()
            quickLinkLabel.setSelectionHandler(UnselectableSelectionHandler())
            quickLinkLabel.items = [page.quickLinkLabel]
            add(quickLinkLabel)

            // add quick links
            let quickLinks = AppStoreQuickLinkDataSource()
            quickLinks.items = page.quickLinks
            add(quickLinks)

            // add footer
            let footer = AppStoreFooterDataSource()
            footer.setSelectionHandler(UnselectableSelectionHandler())
            footer.items = [Void()] // we add 1 element to show the footer, 2 elements will show it twice. 0 will not show it.
            add(footer)
        }
    }
}
  1. 创建最外层数据源。
class AppStoreDataSource: SegmentedDataSource {

    let loading = AppStoreLoadingDataSource()
    let page = AppStoreFeaturedPageDataSource()

    // reload data on index change
    override var selectedDataSourceIndex: Int {
        didSet {
            ds_reusableViewDelegate?.ds_reloadData()
        }
    }

    override init() {
        super.init()
        loading.items = [Void()] // we add 1 element to show the loading, 2 elements will show it twice. 0 will not show it.

        add(loading)
        add(page)
    }
}
  1. 注册单元格。
tableView.ds_register(cellNib: AppStoreFeaturedSectionTableViewCell.self)
tableView.ds_register(cellNib: AppStoreQuickLinkLabelTableViewCell.self)
tableView.ds_register(cellNib: AppStoreQuickLinkTableViewCell.self)
tableView.ds_register(cellNib: AppStoreFooterTableViewCell.self)
tableView.ds_register(cellNib: AppStoreLoadingTableViewCell.self)
  1. 将数据源设置到集合视图中。
tableView.ds_useDataSource(dataSource)
  1. 最后在数据就绪时设置数据。
  // show loading indicator
  dataSource.selectedDataSourceIndex = 0

  // get the data from the service
  service.getFeaturedPage { [weak self] page in

    // update the data source model
    self?.dataSource.page.page = page

    // show the page
    self?.dataSource.selectedDataSourceIndex = 1
}

这样做有很多好处

  1. 轻量级视图控制器。
  2. 您无需再考虑索引了,一切都被我们处理了。只需考虑如何将您的单元格结构化成更小的数据源。
  3. 我们可以轻松地在 UITableViewUICollectionView 之间切换,无需修改数据源或模型。只需更改单元格以继承自 UITableViewCellUICollectionViewCell,其他一切都会正常运作。
  4. 我们可以轻松地添加/删除/更新单元格。例如,我们决定添加更多蓝色链接。我们可以通过只需向传递给数据源的数组中添加新项来完成此操作。
  5. 我们可以根据需要重新排列单元格。只需移动数据源调用中的 add
  6. 最重要的是,我们代码中没有 if/else

查看示例应用程序以获取完整实现。

归属

主要理念来自 [WWDC 2014 高级用户界面与集合视图] (https://developer.apple.com/videos/play/wwdc2014/232/),用泛型编写的 Swift。

作者

Mohamed Afifi, [email protected]

许可协议

GenericDataSource 在 MIT 许可协议下可用。详情请参阅 LICENSE 文件。