RxSwift: UISwitch переключает обратно в исходное состояние - PullRequest
1 голос
/ 28 марта 2019

Я ищу решение проблемы, с которой сталкиваюсь.У меня есть 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 и на основании этого я вызываю 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 должен вернуться в исходное состояние, т. Е. Если он был выключен и пользователь переключил его во включенное состояние, а Api не удалось, он должен вернуться к выключен Штат.

1 Ответ

0 голосов
/ 29 марта 2019

Я бы ожидал увидеть что-то подобное ниже. Что нужно отметить об этом коде:

  • У всех «разрешающих» объектов есть какой-то способ уникальной идентификации каждой ячейки, здесь я использую UUID, но у вас уже может быть какой-то идентификатор.
  • «Разрешения», наблюдаемые в ViewModel, используются для обновления каждой отдельной ячейки. Все ячейки подписываются на это, отображают свой собственный объект Разрешения и отображают его.
  • Как у вас уже есть в вашем контроллере представления, все ячейки отправляют обновленное разрешение через switchToggle Observable.

Приведенный ниже код компилирует и сбрасывает ячейки по мере необходимости. Я полагаюсь на оператора zip, чтобы убедиться, что я совмещаю разрешение, отправленное на запрос, с ответом с сервера. В случае ошибки сервера значениеvalue в соответствующем объекте в словаре будет установлено на противоположное тому, что было отправлено на сервер.

Чем больше проницательных наблюдателей (предназначенных для каламбура) из приведенного ниже кода, вы заметите, что при сбое запроса к серверу объект permissions будет излучать, но на самом деле не будет изменять состояние, поскольку это был переключатель , который был переключен, а не 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)
    }
}
...