4

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

我们拥有和需要什么:
1. 带有无限滚动处理程序 (SVPullToRefresh) 的 TableView
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子请求,然后调用成功处理程序并收集所有 10 个响应。此外,某些特定子请求的失败不应影响其他正在运行的子请求
3.用户可以更改他的搜索请求,而无需等待整个请求过程完成。这意味着一旦用户更改了一些参数,我将清除所有项目,我需要parent request在所有项目中取消sub-requests并重新开始这一切。
4.除了#2,有时用户可以向下滚动以获取新的项目部分。这将意味着 newparent request应该开始,但是sub-requests从之前的响应parent request应该继续工作
5.所有请求都应该在 取消self.deinit,所以这一切都应该只在 期间有效self.lifetime,但我不确定放置此参数的正确位置是什么

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


谢谢大家的帮助

4

2 回答 2

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()

于 2017-04-27T12:48:57.993 回答
0

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

对于第 1 点,我做了这个:

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。所以,这对我来说很好,它会在self被销毁时自动处理请求

对于其他点,我做了这个:

我的想法是我正在为表格加载一些项目,然后我需要为每个项目发送额外的请求以获取它的详细信息。所以,我创建了类,有 3 个属性 - item, itemDetail, 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我打电话cell.detailsObserver.send(value: self.items[indexPath.row].details)

而且,当调用 VCdeinit或执行新main请求时,所有请求都会自动取消,因为当我使用self.items.removeAll()它时会处理所有请求。

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

于 2017-04-27T10:10:47.077 回答