【问题标题】:RxSwift, invoking a network callRxSwift,调用网络调用
【发布时间】:2021-04-30 18:33:40
【问题描述】:

我是 Rx 的新手,正在尝试一个网络调用。

我可以这样做:

struct Genre: Codable {
var genres: [Genres]?
}

struct Genres: Codable {
var id: Int?
var name: String?
 }

final class GenreViewModel {

let disposeBag = DisposeBag()

var networking: Networking!

let getGeners = PublishRelay<[Genres]>()

var items: PublishRelay<[Genres]>?
var itemsDriver: Driver<[Genres]>?
let isLoading: Driver<Bool>


init(networking: Networking = Networking()) {
    self.networking = networking

    
    let shouldLoadItems = Observable.merge(
    ).debug("merge.debug(????)")
    .startWith(())
    
    let gg = shouldLoadItems.flatMap {
        networking.preformNetwokTask(
            endPoint: TheMoviedbApi.genre,
            type: Genre.self)
            .debug("???? network call")
    }
    
    isLoading = Observable.merge(
        shouldLoadItems.map { true },
        gg.map { _ in false }
    )
    .asDriver(onErrorJustReturn: false).debug("???? is loading")
    
    itemsDriver = gg
        .map { $0.genres! }
        .asDriver(onErrorJustReturn: []).debug("????drive")
    
}

我正在尝试寻找一种不使用“let shouldLoadItems”的方法。 类似的东西:

final class GenreViewModel {

let disposeBag = DisposeBag()

var networking: Networking!

let getGeners = PublishRelay<[Genres]>()

var items: PublishRelay<[Genres]>?
var itemsDriver: Driver<[Genres]>?
let isLoading: Driver<Bool>


init(networking: Networking = Networking()) {
    self.networking = networking
    
   let geners =  getGeners
        .flatMap { geners in
            networking.preformNetwokTask(
                endPoint: TheMoviedbApi.genre,             
               type: Genre.self)
              .debug("???? network call not in use")
       }.startWith(())
       .share()


    
    isLoading = Observable.merge(
        shouldLoadItems.map { true },
        gg.map { _ in false }
    )
    .asDriver(onErrorJustReturn: false).debug("???? is loading")

    
    itemsDriver = geners
        .map { $0.genres! }
        .asDriver(onErrorJustReturn: []).debug("????drive")
    
}

VC:

func bindRx() {
    viewModel.isLoading
        .drive(hud.rx.animation)
        .disposed(by: disposeBag)
   
        
    
    viewModel.itemsDriver?.drive(collectionView.rx.items(cellIdentifier: GenreCollectionViewCell.reuseIdentifier, cellType: GenreCollectionViewCell.self)) { (row,item,cell) in
        cell.config(item: item)
    }.disposed(by: disposeBag)
}

但让基因不叫。 我错过了什么?

【问题讨论】:

  • 看起来您没有分别在 ObservableDriver 上使用 subscribedrive。 (也不要忘记dispose。)
  • @Vym 你能告诉我我应该在哪里订阅吗?
  • 你真的同时拥有Genres 类型和Genre 类型吗?你能展示这些结构吗?
  • 网络调用是什么原因?
  • 主题和中继永远不应使用var 定义,始终使用let

标签: ios swift mvvm rx-swift


【解决方案1】:

我希望 cmets 中的所有问题都有点痛苦,但这个问题中缺少的是“函数式反应式编程”的“反应式”部分。

在 FRP 中,网络请求不会单独发生。它通常由事件生产者触发并提供给事件消费者。为了让请求发生,必须存在一个事件消费者。

视图模型本身并没有连接到任何东西,什么都不做。为了让您的社交活动发生,something 必须在监听结果。您的视图模型就像您家中的管道。除非有人打开水龙头,否则水不会流动。

struct GenreViewModel {
    let items: Observable<[Genres]>
    let error: Observable<Error>
    let isLoading: Observable<Bool>

    init(networking: Networking) {
        let result = networking.preformNetwokTask(endPoint: TheMoviedbApi.genre, type: Genre.self)
            .compactMap(\.genres)
            .materialize()
            .share(replay: 1)

        items = result
            .compactMap { $0.element }
        error = result
            .compactMap { $0.error }
        isLoading = result
            .map { _ in false }
            .startWith(true)
    }
}

final class GenreViewController: UIViewController {
    var tableView: UITableView!
    var activityIndicatorView: UIActivityIndicatorView!
    var viewModel: GenreViewModel!
    let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel.items
            .bind(to: tableView.rx.items(cellIdentifier: "Cell")) { _, genres, cell in
                cell.textLabel?.text = genres.name
            }
            .disposed(by: disposeBag)

        viewModel.error
            .bind(onNext: presentScene(animated: true) {
                UIAlertController(title: "Error", message: $0.localizedDescription, preferredStyle: .alert)
                    .scene { $0.connectOK() }
            })
            .disposed(by: disposeBag)

        viewModel.isLoading
            .bind(to: activityIndicatorView.rx.isAnimating)
            .disposed(by: disposeBag)
    }
}

在上面的代码中,网络请求将在bind 调用执行后立即开始。如果发出错误,它会被路由到 error Observable 并显示带有错误消息的 UIAlertController(它使用 CLE-Architecture-Tools 来执行此操作。)如果成功,流派对象的名称将显示在表中查看。

【讨论】:

  • 我已经添加了我所做的 vc
  • 你能告诉我我的例子中缺少什么吗?触发器是什么?
  • 在您的特定情况下,没有外部触发器。订阅本身就是触发器。根据您的代码,这就是让您失望的原因。
  • 所以 viewModel.itemsDriver?.drive 不是触发器?那么我应该如何在我的示例中执行此操作以触发网络调用?订阅?
  • 在您的第二个视图模型中,您有 getGeners 作为触发器,但您没有发出值。在这种情况下仅订阅是不够的,您的触发器还必须发出一个值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-08
相关资源
最近更新 更多