ReactiveCocoa 5,ReactiveSwift网络子请求处理&最佳实践

时间:2017-04-25 17:58:48

标签: ios swift reactive-cocoa racsignal reactive-swift

我试图找到最佳做法来处理从父请求获得的每个值的多个子请求。我尝试使用与此处相同的逻辑 - Reactive Cocoa 5 and ReactiveSwift network requests handling,但遇到了一些问题。

我们拥有和需要的东西:
1。带有无限滚动处理程序的TableView(SVPullToRefresh)
2。每次调用处理程序时获取对象列表
3。发送"子请求"来自回复的每个对象

备注:
1.一旦viewController关闭(deinit调用)
,所有请求(父+子请求)都将被取消 2.我需要有能力随时取消父请求。这也应该取消所有子请求。

我目前拥有什么

我知道我在"无限处理程序"是有点"胶带",但我是ReactiveSwift的新手......

self.tableView.addInfiniteScrollingWithActionHandler { [unowned self] in
    self.tempMutableProperty.value = true
}

self.tempMutableProperty.producer.skipNil().flatMap(.latest) { [unowned self] tempValueThatIDontNeed in
    return self.producerForParentRequest(offset: self.offset)
        .take(during: self.reactive.lifetime)
        .on(
            // handlers for errors, completed, etc
            value: { [unowned self] items in
                self.items.append(items)
                self.tableView.reloadData()
                self.offset += items.count
                // SEND REQUEST #2 FOR EACH ITEM
            }
    ).flatMapError { error in
        return SignalProducer.empty
    }
}.observe(on: UIScheduler().start()

所以,正如你所看到的,我对tableView进行了分页。我正在为每个页面提取对象列表。然后,对于响应中的每个项目,我需要使用请求#2获取其他信息。

流量和问题:
1。当然我想摆脱tempMutableProperty并以某种方式启动新的parent request 2。每个sub-request应该是独立的,这意味着我希望分别为每个value/error调用sub-request处理程序,而不是等待所有10个子-requests然后调用成功处理程序,收集所有10个响应。此外,某些特定子请求失败不应影响其他运行的子请求 3. 用户可以在不等待整个请求流程完成的情况下更改其搜索请求。这意味着,一旦用户更改了某些参数,我将清除所有项目,并且我需要在所有parent request内取消sub-requests并重新开始。
4. 除了#2之外,有时用户可以向下滚动以获取项目的新部分。这意味着应该启动新的parent request,但sub-requests之前的回复parent request应该继续工作 5。所有请求都应该在self.deinit上取消,所以这一切都应该只在self.lifetime期间有效,但我不确定这个地方的正确位置是什么参数

我不确定如果不将一次性/信号存储为自己的属性,是否所有这一切都是可能的,因此如果sub-request将以某种方式存储为属性,那么这不是问题。

谢谢大家的帮助

2 个答案:

答案 0 :(得分:0)

所以,我会在这里发布我的问题的解决方案。

对于第1点我已经做到了:

update table_name set column_name = replace (column_name , 'oldstring' ,'newstring') where column_name like 'oldstring%'

这帮助我摆脱了let disposable = SerialDisposable() self.tableView.addInfiniteScrolling(actionHandler: { [unowned self] in self.disposable.inner = nil // this is needed to force dispose current request before starting new one self.disposable.inner = self.producer().take(during: self.reactive.lifetime) .on(value: { [unowned self] value in // handle as you want }).start() }) 。而不是tempMutableProperty使用flatMap。 所以,这对我来说很好,并且当SerialDisposable被破坏时它会自动处理请求

其他要点我做了这个:

我的想法是我正在为表加载一些项目,然后我需要为每个项目发送额外的请求以获取它的详细信息。所以,我创建了一个类,有3个属性 - selfitemitemDetail

然后在requestSent我有

willDisplay cell

注意func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { if !self.items[indexPath.row].requestSent { self.items[indexPath.row].details <~ self.detailedProducerForItemID(self.items[indexPath.row].item.id) self.items[indexPath.row].requestSent = true } } self.items[indexPath.row].details

在用于表示细节的单元格本身中,我有类似的内容:

MutableProperty<Details?>,其中let (detailsSignal, detailsObserver) = Signal<MutableProperty<Details?>, NoError>.pipe()是项目详情的类名称。

在单元格的Details中:

awakeFromNib

let details = self.detailsSignal.flatMap(.latest) { $0.producer } self.detailsLabel.reactive.text <~ details.map { value -> String? in // handling `Details` } 中,我致电cellForRow

并且,当调用VC的cell.detailsObserver.send(value: self.items[indexPath.row].details)时,或者我执行新的deinit请求时,所有请求都会自动取消,因为当我使用main时,它会处理所有请求。

这是一个粗略的流程。如果有人对更多细节感兴趣,请不要犹豫。

答案 1 :(得分:0)

对于第1部分,我将添加一个扩展,将无限滚动动作处理转换为信号:

extension Reactive where Base: UITableView {
    public func infiniteScrollingSignal() -> Signal<Void, NoError>
    {
        return Signal { [unowned base = self.base] observer in
            base.addInfiniteScrollingWithActionHandler  {
                observer.send(value: ())
            }

            return ActionDisposable {
                // Unsubscribe the infinite scrolling action handler here if necessary
            }
        }
        .take(during: self.lifetime)
    }
}

然后,您可以将所有逻辑连接到self.tableView.reactive.infiniteScrollingSignal()