【问题标题】:rxswift viewmodel with input output带有输入输出的 rxswift 视图模型
【发布时间】:2023-05-20 18:29:01
【问题描述】:

我正在尝试在来自 RxSwift repo 的 rxswift 示例项目中实现类似的功能。但在我的情况下,有依赖的可观察量。如果不使用视图模型中的绑定,我找不到任何解决方案

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

首先是输入、输出和视图模型的定义

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 { $0.offset != index ? $0.element : nil }
        }
        .asDriver(onErrorJustReturn: [])

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

    return userList
}

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

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

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

【问题讨论】:

    标签: ios swift mvvm rx-swift frp


    【解决方案1】:

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

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

    let userListViewModel: UserListViewModel = { input, loadUsers in
    
        enum Action {
            case reset([User])
            case delete(at: Int)
        }
    
        let resetUsers = input.viewAppearAction
            .flatMapLatest { loadUsers().materialize() }
            .compactMap { $0.element }
            .map { Action.reset($0) }
    
        let delete = input.deleteAction.map { Action.delete(at: $0) }
    
        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: [])
    }
    

    【讨论】:

    • 那么诀窍是将所有影响状态的动作放入扫描算子中?
    • 是的,这就是它的本质。这实际上是一个摩尔状态机。
    最近更新 更多