使用 Swift 实现 简单的 UITableViewDataSource 泛型支持

2015-06-05 23:40:44 +08:00
 banxi1988

UITableViewDataSource的简单泛型实现

在日常的 iOS 开发中, UITableView是用得特别多的.

也许使用的最多的是 UITableViewController 了,重写需要的几个方法就OK了.
从 iOS 2.0 到 iOS 8 UITableView 本身也在不断的进化. 后来出现了 UICollectionView
当我在 UITableViewController 重复做着类似的事情时,
我遇到了 objc.io 它第一期中文章: Lighter View Controllers
他让我认识到,我以前对 Apple 提供的这一套东西,接受却缺少反思(不过在我看这文章之前,我还没正式做 iOS 开发)
但是,虽然篇文章,写我觉得写 UITableView的代码写得很漂亮的, 但是重复的代码还在不断的写,
于是我想起了 Android 平台的 ArrayAdapter, 我知道很多人都是继承 BaseAdapter的, 但是继承ArrayAdapter却会有更多的好处.
比如有泛型一些 Stub代码就不用了.
那么在 iOS 中我要怎么做呢? 幸好 Swift 为我们也带来的泛型

UITableViewDataSource 泛型 的使用

先从一个使用实例说起, 例如我需要一个文章列表的 UITableViewDataSource
那么我只需要写如下的代码即可:

class ArticleItemTableViewDataSource<T:ArticleItem>:GenericDataSource<T>{

    init(articleItems:[T]){
        super.init(items:articleItems)
    }

    override func configureTableViewCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
        let itemCell = cell as! ArticleItemTableViewCell
        let item = itemAtIndexPath(indexPath)
        itemCell.bind(item)
    }

    override class var reuseIdentifier:String{
        return ArticleItemTableViewCell.reuseIdentifier
    }

}

然后就可以用了:

tableView.registerNib(ArticleItemTableViewCell.nib, forCellReuseIdentifier: ArticleItemTableViewCell.reuseIdentifier)
        dataSource = ArticleItemTableViewDataSource(articleItems: [])
        tableView.dataSource = dataSource

UITableViewDataSource 泛型的实现

实现泛型的基类GenericDataSource 却是有一点曲折.
因为 Swift 为了与 Objective-C的交互性,做了一些限制 不能直接在 UITableView的方法中使用泛型类型的参数 .

所以必须再加一层包装, 这也就是我所实现的 GenericDataSource

class GenericDataSource<T>:SimpleDataSourceBridge{
    private var items = [T]()

    init(items:[T]){
        self.items = items
    }

    func updateItems(items:[T]){
        self.items = items
    }

    func itemAtIndexPath(indexPath:NSIndexPath) -> T{
        return items[indexPath.row]
    }

    override func numberOfRows() -> Int {
        return self.items.count
    }

}

而让 SimpleDataSourceBridge 不直接调用泛型的方法,而是调用实现的另一个方法:
即如此:

final func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numberOfRows()
    }

注意上面方法的修饰 final 这是为了保证子类不再重写些方法了. 而应该去重写numberOfRows()方法.
而这方法在泛型类中已经实现

到此一个支持泛型的 UITableViewDataSource 基类这是这样样子了, 我使用起来觉得很开心
两个类,全部源代码在这里:
https://gist.github.com/banxi1988/cbd5953dea41d20c833e

值得注意的地方

  1. 以我一贯的性格, 我的目的是让他减少我 80% 场景的代码编写, 所以,如果需要有变,需要自行修改代码
  2. 泛型的子类也得是泛型,所以注意我使用的子类的
    class ArticleItemTableViewDataSource<T:ArticleItem>:GenericDataSource<T>

  3. 可以看到代码,基于对于弱化的 UICollectionView 也提供了支持. 简单的情况也可使用.

最后: 希望对大家有帮助.

3972 次点击
所在节点    iDev
5 条回复
Elethom
2015-06-06 01:21:21 +08:00
類似 view model?
wezzard
2015-06-06 01:30:03 +08:00
如果樓主曾經接觸過 OS X 開發,應該會知道 NSController 及其子類。蘋果沒遷移到 iOS 上而已。
banxi1988
2015-06-06 08:04:13 +08:00
@wezzard 多谢指点. 我还没有接触 OS X 开发. 等我对 NSController 多些了解,也许就能明显你的想法了.
ios
2015-06-06 10:04:10 +08:00
不错 之前使用Xamarin的时候我也用C# 泛型写这个 DataSource
很方便使用
mailworks
2015-06-07 17:50:29 +08:00
能不能放个Demo呢?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/196444

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX