【问题标题】:RxSwift: UISwitch toggle back to initial StateRxSwift:UISwitch 切换回初始状态
【发布时间】:2019-03-28 19:39:13
【问题描述】:

我正在为我面临的问题寻找解决方案。我有 TableView,它有多个单元格,每个单元格都有一个 UISwitch 并且该开关的状态(开/关)设置如下:

viewModel.permissions
        .drive(tblMessageTypes.rx.items(cellIdentifier: "PermissionCellIdentifier", cellType: PermissionTableViewCell.self)) { [switchSubject] _, item, cell in
            cell.backgroundColor = .clear
            cell.lblTitle.text = item.permissionTitle
            cell.lblDetail.text = item.permissionDescirption
            cell.selectionStyle = .none
            cell.switchPermission.isOn = item.permissionValue
            cell.switchPermission.isEnabled = !item.isPermissionReadOnly

            cell.switchPermission.rx.controlEvent(.valueChanged)
                .withLatestFrom(cell.switchPermission.rx.value)
                .map { isOn in
                    var newPermission = item
                    newPermission.permissionValue = isOn
                    return newPermission
                }
                .bind(to: switchSubject)
                .disposed(by: cell.disposeBag)
        }
        .disposed(by: disposeBag)

因此,当切换 Switch 时,我将通过更新 Switch 状态传递当前单元格值,并基于此在我的 VM 中调用 api,如下所示:

let serverReponse =  inputs.switchToggle
        .map { permission in
            let dicto = permission.toDictionary()
            let parameters = ["permissions": [dicto]]
            return parameters
        } .flatMapLatest { parameters in
            userService.updateUserPermission(parameters: parameters)
                .trackActivity(inputs.indicator)
                .materialize()
        }
        .share()

现在我遇到的问题是,如果 api 由于任何原因失败,UISwitch 应该如何回退到初始状态,即如果它是 Off 并且用户将其切换到 On 状态并且 Api 失败,它应该回退到 Off 状态。

【问题讨论】:

    标签: ios swift rx-swift reactive rx-cocoa


    【解决方案1】:

    我希望看到类似下面的内容。这段代码的注意事项:

    • 所有“权限”对象都有某种方式来唯一标识每个单元格,我在这里使用的是 UUID,但您可能已经有了某种 ID。
    • ViewModel 中的“权限”Observable 用于更新每个单独的单元格。所有的单元格都订阅这个,映射出他们自己的 Permission 对象并显示它。
    • 正如您在视图控制器中已经拥有的那样,所有单元格都通过 switchToggle Observable 发送更新的权限。

    以下代码根据需要编译和重置单元格。我依靠zip 运算符来确保我将发送给请求的权限与来自服务器的响应相结合。如果服务器出错,字典中相应对象中的权限值将设置为与发送到服务器的相反值。

    下面代码的更精明的观察者(双关语),你会注意到当服务器请求失败时,permissions 对象会发出,但它实际上不会改变状态,因为它是 switch 被切换,而不是字典中的 permissionValue。但是,该发射将被开关拾取,这将导致其自行重置。

    struct Inputs {
        let initialPermissions: [Permission]
        let switchToggle: Observable<Permission>
    }
    
    struct ViewModel {
    
        let permissions: Observable<[UUID: Permission]>
    
        init(_ inputs: Inputs, userService: UserService) {
            let serverReponse =  inputs.switchToggle
                .map { permission in
                    let dicto = permission.toDictionary()
                    let parameters = ["permissions": [dicto]]
                    return parameters
                }
                .flatMapLatest { parameters in
                    userService.updateUserPermission(parameters: parameters)
                        .materialize()
                }
                .share()
    
            let perms = Dictionary(grouping: inputs.initialPermissions, by: { $0.id })
                .mapValues { $0.first! }
    
            permissions = Observable.zip(inputs.switchToggle, serverReponse)
                .filter { $0.1.error != nil }
                .map { Permission(id: $0.0.id, permissionValue: !$0.0.permissionValue) }
                .scan(into: perms, accumulator: { state, update in
                    state[update.id] = update
                })
                .startWith(perms)
        }
    }
    

    【讨论】:

    • 我尝试了您提供的解决方案,但我无法执行此操作:let perms = Dictionary(grouping: inputs.initialPermissions, by: { $0.id }) .mapValues { $0.first! },因为我没有从我的 VC 传递 [Permission],因为我的 VM 中有 Observable[Permission]。你能告诉我如何重构上面的代码来解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 2019-01-30
    • 2019-05-08
    • 2019-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-30
    • 2010-12-27
    相关资源
    最近更新 更多