RxDataSource创建UITableView - I

我们继续完成App的后半部分,基于RxDatasource,用reactive的方式处理UITableView


准备工作

为了方便演示,基于上个视频完成的例子,我们做了一些额外的准备工作

首先,我们给UITableView添加了一个Cell,在这个Cell里:

image
  • 我们用一个UILabel和一个UITextView构成了一个垂直布局的StackView,表示项目的名字和描述;
  • 用一个UIImageView和之前的StackView又构成了一个水平布局的StackView,最终形成了整个Cell的内容;

在这里,有一个技巧,我们可以在Stroyboard里,为Cell设置一个背景色,这样方便我们观察一个Cell里实际可以摆放内容的区域的大小;

其次,我们新建了一个叫做RepositoryInfoTableVieweCell的class,表示我们新创建的Cell。它定义我们需要访问的三个IBOutlet:

class RepositoryInfoTableViewCell: UITableViewCell {

    @IBOutlet weak var avatar: UIImageView!
    @IBOutlet weak var name: UILabel!
    @IBOutlet weak var detail: UITextView!

}

由于我们在Storyboard里设置了背景色,我们需要在awakeFromNib方法里,去掉它:

override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
    self.backgroundColor = UIColor.clearColor()
}

第三,我们新建了一个struct RepositoryModel,表示Github返回的各种结果,我们将使用这个Model为RepositoryInfoTableViewCell赋值。并且,我们修改了searchForGithubparseGithubResponse,使得最终我们可以直接订阅到一个Observable<[RespositoryModel]>

第四,我们暂时去掉了self.repositoryName.rx_textsubscribeNext订阅,稍后,我们采用新的方式来订阅这个事件序列;

第五,我们在ViewController extension里,新添加了一个方法,用一个UIAlertController显示错误信息:

private func displayErrorAlert(error: NSError) {
    let alert = UIAlertController(
        title: "Network error",
        message: error.localizedDescription,
        preferredStyle: .Alert)

    alert.addAction(UIAlertAction(title: "OK",
        style: UIAlertActionStyle.Default,
        handler: nil))

    self.presentViewController(alert, 
        animated: true, completion: nil)
}

最后,我们通过Cocoapods新安装了一个叫做RxDatasource的Swift模块:

# Uncomment this line to define a global platform for your project
platform :ios, '9.0'
# Uncomment this line if you're using Swift
use_frameworks!

target 'RxNetworkDemo' do
    pod 'Alamofire', '~> 3.4'
    pod 'RxSwift',    '~> 2.0'
    pod 'RxCocoa',    '~> 2.0'
    pod 'RxDataSources', '~> 0.7' # Our new swift module for data source
    pod 'SwiftyJSON', :git => 'https://github.com/SwiftyJSON/SwiftyJSON.git'
end

准备完成之后,我们就可以开工了。


处理请求错误

在开始构建UITableView之前,我们先进一步完善网络请求的部分。当请求错误时,我们直接把Alamofire返回的错误消息封装成了.Error事件。于是,我们可以这样来订阅请求成功和失败事件:

.subscribe(
    onNext: { repositoryModelArray in
        // We will create UITableView here later
    },
    onError: { error in
        let err = error as NSError
        self.displayErrorAlert(err)
    })

在上面这个例子里,我们分别通过onNextonError参数传递了处理成功和失败事件的closure,其实这个版本的subscribe还有另外两个参数,是onCompletedonDisposed,它们分别用于订阅事件序列的结束和回收。这样,要比我们在subscribe中使用switch...case...检查事件值方便一些。

但是,在我们这个例子里,由于我们使用了.flatMap,因此,我们是订阅不到网络请求事件序列中的.Completed事件的,它和UITextField输入事件序列的.Completed事件合并在一起了。

接下来,如果我们把searchForGithub中,请求的ur,由https改为http:

let url = "http://api.github.com/search/repositories"

重新编译执行,就可以看到相应的错误提示了:

image

用Rx的方式加载UITableView

接下来,我们使用RxSwift,把Github的返回结果显示在下面的UITableView上。RxSwift允许我们通过几种不同的方式,通过订阅一个事件序列生成对应table cell对象,先来看最简单的一种。

首先,在网络请求成功的onNext部分,我们先重置searchResultdataSource

self.searchResult.dataSource = nil

这是因为,每一次网络请求之后,我们需要重新订阅新的Observable来创建UITableView,如果不清空data source,RxSwift会报错。


一个复杂的bindTo

在订阅Github返回结果之前,我们要先了解一个略显复杂的bindTo的用法,它的声明是这样的:

public func bindTo<R1, R2>(
    binder: Self -> R1 -> R2, 
    curriedArgument: R1) -> R2

这里,参数binder仍旧用于指定一个订阅者,不同的是,这个订阅者可以接受一个closure做为参数,这个closure参数由bindTo的第二个参数,curriedArgument指定。简单来说,binder可以调用curriedArgument指定的方法。

为什么要提到这个版本的bindTo呢?是因为我们要通过这样的方式来订阅self.item。为了简化代码,我们先定义一些typealias

typealias O = Observable<[RepositoryModal]>
typealias CC = (Int, RepositoryModel, 
    RepositoryInfoTableViewCell) -> Void

然后,我们先来实现binder

let binder: O -> CC -> Disposable =
    self.searchResult.rx_itemsWithCellIdentifier(
        "RepositoryInfoCell",
        cellType: 
            RepositoryInfoTableViewCell.self)

rx_itemsWithCellIdentifierRxSwiftUITableView添加的扩展,用于根据事件序列的值生成UITableView的每一行。它的返回值是一个Observer,也就是传递给bindTo方法的第一个参数。

但是,rx_itemsWithCellIdentifier还需要调用另外一个Closure,用于执行具体的UITableViewCell的设置,这个Closure就是我们要传递给bindTo的第二个参数,curriedArgument:

let curriedArgument = { (
    rowIndex: Int,
    element: RepositoryModel,
    cell: RepositoryInfoTableViewCell) in

    cell.name?.text = element.name
    cell.detail?.text = element.detail
}

这个Closure有三个参数:

  • 第一个参数是每一个Section里,row的索引。rx_itemsWithCellIdentifier只能生成只有一个Section的UITableView
  • 第二个参数,是用于生成每一个Cell需要的内容,在我们的例子里,就是一个RepositoryModel对象;
  • 第三个参数,表示要生成的Cell对象,也就是RepositoryInfoTableViewCell对象;

接下来,在这个Closure内部,我们只是简单的设置了项目名称以及描述。

现在,bindercurriedArgument都已齐备,我们可以调用bindTo通过订阅self.item创建UITableView了,和我们之前的代码相比,这反而是最简单的一步。我们先用Observable.just把Github的返回值包装成一个事件序列,然后,使用bindTo订阅它:

Observable.just(repositoryModelArray)
    .bindTo(binder, 
        curriedArgument: curriedArgument)
    .addDisposableTo(self.bag)

然后,Command + R编译执行,就可以看到结果了。并且,输入不同的内容,UITableView可以自动更新:

image

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容