ReactiveCocoa 5, обработка подзапросов в сети ReactiveSwift и лучшие практики

Я пытаюсь найти лучшую практику для обработки нескольких подзапросов для каждого значения, полученного из родительского запроса. Я пытаюсь использовать ту же логику, что и здесь, - обработка сетевых запросов Reactive Cocoa 5 и ReactiveSwift, но есть некоторые проблемы.

Что нам нужно и нужно:
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 подзапросов и затем вызывает обработчик успеха со всеми 10 собранными ответами. Кроме того, сбой в некоторых конкретных подзапросах не должен влиять на другие выполняющиеся подзапросы.
3. Пользователь может изменить свой поисковый запрос, не дожидаясь завершения всего процесса запроса. Это означает, что, как только пользователь изменит некоторые параметры, я удалю все элементы, и мне нужно отменить parent request во всех sub-requests и начать все это снова.
4. В дополнение к #2, иногда пользователь может прокрутить вниз, чтобы получить новую порцию предметов. Это будет означать, что новый parent request должен начать, но sub-requests из предыдущего ответа parent request должен продолжать работать
5. Все запросы должны быть отменены на self.deinitтак что все это должно работать только во время self.lifetime, но я не уверен, как правильно разместить этот параметр

Я не уверен, что все это возможно без сохранения одноразовых / сигналов как свойств себя, так что это не проблема, если sub-request будет как-то храниться как свойства.


Спасибо за вашу помощь

2 ответа

Для первой части я бы добавил расширение, которое превращает обработку действия бесконечной прокрутки в сигнал:

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

Итак, я опубликую здесь решения для моих проблем.

Для пункта № 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)

И когда ВК deinit называется, или я выполняю новый main запрос, все запросы автоматически отменяются, так как, когда я использую self.items.removeAll() он распоряжается всеми запросами.

Это грубый поток. Если кто-то заинтересован в более подробной информации, не стесняйтесь спрашивать.

Другие вопросы по тегам