具有输入输出的 rxswift viewmodel

rxswift viewmodel with input output

我正在尝试在 RxSwift repo 的 rxswift 示例项目中实现类似的东西。但就我而言,有依赖的可观察量。如果不在 viewmodel

中使用绑定,我找不到任何解决方案

这是我的视图模型的结构:

首先是输入、输出和viewmodel的定义

typealias UserListViewModelInput = (
    viewAppearAction: Observable<Void>,
    deleteAction: Observable<Int>
)

typealias UserListViewModelOutput = Driver<[User]>

typealias UserListViewModel = (UserListViewModelInput, @escaping UserApi) -> UserListViewModelOutput

然后是无法编译的实际实现。

let userListViewModel: UserListViewModel = { input, loadUsers in

    let loadedUserList = input.viewAppearAction
        .flatMapLatest { loadUsers().materialize() }
        .elements()
        .asDriver(onErrorDriveWith: .never())

    let userListAfterDelete = input.deleteAction
        .withLatestFrom(userList) { index, users in
            users.enumerated().compactMap { [=11=].offset != index ? [=11=].element : nil }
        }
        .asDriver(onErrorJustReturn: [])

    let userList = Driver.merge([loadedUserList, userListAfterDelete])

    return userList
}

Viewmodel 有两个工作。首先加载用户列表。其次是删除索引处的用户。最终输出是下载的用户列表,其中 UserApi 减去已删除的用户。

这里的问题为了定义userList 我需要定义userListAfterDelete。为了定义 userListAfterDelete 我需要定义 userList.

那么有没有办法在不使用视图模型内部绑定的情况下打破这个循环?就像保持状态的占位符 observable 或运算符?

这是状态机的工作。您将在下面的代码中看到有两个操作可以影响 User 数组。当视图出现时,将下载一个新数组,当出现删除时,将删除特定用户。

这可能是处理状态的反应式代码中最常见的模式。如此普遍以至于有整个库实现了它的一些变体。

let userListViewModel: UserListViewModel = { input, loadUsers in

    enum Action {
        case reset([User])
        case delete(at: Int)
    }

    let resetUsers = input.viewAppearAction
        .flatMapLatest { loadUsers().materialize() }
        .compactMap { [=10=].element }
        .map { Action.reset([=10=]) }

    let delete = input.deleteAction.map { Action.delete(at: [=10=]) }

    return Observable.merge(resetUsers, delete)
        .scan(into: [User](), accumulator: { users, action in
            switch action {
            case let .reset(newUsers):
                users = newUsers
            case let .delete(index):
                users.remove(at: index)
            }
        })
        .asDriver(onErrorJustReturn: [])
}