ios - 只有一个开关打开

标签 ios swift functional-programming switch-statement rx-swift

我正在努力应对以下挑战。我使用包含开关的自定义单元格创建了表格 View 。我只想打开一个开关,例如,发射后我打开第三个开关,然后我打开第七个开关,因此第三个开关关闭,依此类推。我对单元使用 rx + 协议(protocol),并且一直不明白如何确定切换哪个开关。以前我打算使用过滤器或映射在 dataSource 数组中查找哪个开关打开并以某种方式处理这个问题,但现在我搞砸了。我不确定不使用 TableView 委托(delegate)方法是否可行。非常感谢,希望有人能解释我错在哪里。

//我的单元格是这样的:enter image description here

//CellViewModel 实现

    import Foundation
    import RxSwift

protocol ViewModelProtocol {
    var bag:DisposeBag {get set}

    func dispose()
}

class ViewModel:ViewModelProtocol {
    var bag = DisposeBag()

    func dispose() {
        self.bag = DisposeBag()
    }
}


protocol CellViewModelProtocol:ViewModelProtocol {
    var isSwitchOn:BehaviorSubject<Bool> {get set}
}

class CellVM:ViewModel, CellViewModelProtocol {
    var isSwitchOn: BehaviorSubject<BooleanLiteralType> = BehaviorSubject(value: false)

    let internalBag = DisposeBag()

    override init() {

    }

}

//我的 Cell 实现
import UIKit
import RxSwift
import RxCocoa

class Cell:UITableViewCell {

    static let identifier = "cell"

    @IBOutlet weak var stateSwitch:UISwitch!

    var vm:CellViewModelProtocol? {
        didSet {
            oldValue?.dispose()
            self.bindUI()
        }
    }

    var currentTag:Int?

    var bag = DisposeBag()

    override func awakeFromNib() {
        super.awakeFromNib()
        self.bindUI()
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        self.bag = DisposeBag()
    }


    private func bindUI() {
        guard let vm = self.vm else { return }

        self.stateSwitch.rx.controlEvent(.valueChanged).withLatestFrom(self.stateSwitch.rx.value).observeOn(MainScheduler.asyncInstance).bind(to: vm.isSwitchOn).disposed(by: vm.bag)

    }
}

//TableViewController 实现
import UIKit
import RxSwift
import RxCocoa

class TableViewController: UITableViewController {

    private var dataSource:[CellViewModelProtocol] = []

    var vm = TableViewControllerVM()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.estimatedRowHeight = 70
        self.tableView.rowHeight = UITableView.automaticDimension
        self.bindUI()
    }

    private func bindUI() {
        vm.dataSource.observeOn(MainScheduler.asyncInstance).bind { [weak self] (dataSource) in
            self?.dataSource = dataSource
            self?.tableView.reloadData()
        }.disposed(by: vm.bag)
    }


    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.dataSource.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: Cell.identifier, for: indexPath) as! Cell

        if cell.vm == nil {
            cell.vm = CellVM()
        }

        return cell
    }

}

class TableViewControllerVM:ViewModel {

    var dataSource:BehaviorSubject<[CellViewModelProtocol]> = BehaviorSubject(value: [])

    let internalBag = DisposeBag()

    override init() {
        super.init()
        dataSource.onNext(createDataSourceOf(size: 7))
        self.handleState()
    }

    private func createDataSourceOf(size:Int) -> [CellViewModelProtocol] {
        var arr:[CellViewModelProtocol] = []
        for _ in 0..<size {
            let cell = CellVM()
            arr.append(cell)
        }
        return arr
    }

    private func handleState() {

    }
}

最佳答案

也许这段代码会帮助你:

extension TableViewController {
    // called from viewDidLoad
    func bind() {
        let cells = (0..<7).map { _ in UUID() } // each cell needs an ID
        let active = ReplaySubject<UUID>.create(bufferSize: 1) // tracks which is the currently active cell by ID

        Observable.just(cells) // wrap the array in an Observable
            .bind(to: tableView.rx.items(cellIdentifier: "Cell", cellType: Cell.self)) { _, element, cell in
                // this subscription causes the inactive cells to turn off
                active
                    .map { $0 == element }
                    .bind(to: cell.toggleSwitch.rx.isOn)
                    .disposed(by: cell.disposeBag)

                // this subscription watches for when a cell is set to on.
                cell.toggleSwitch.rx.isOn
                    .filter { $0 }
                    .map { _ in element }
                    .bind(to: active)
                    .disposed(by: cell.disposeBag)
            }
            .disposed(by: disposeBag)
    }
}

关于ios - 只有一个开关打开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62260402/

相关文章:

iphone - 如何在后台将图像从网站保存到 iphone 应用程序(并快速完成)?

ios - Xcode项目中添加嵌入式框架时,如何区分Debug和Release?

ios - 我不能在 switch 内沮丧吗? ( swift 3)

java - 使用 collect 保留 Java 流中的顺序

design-patterns - 双折功能图案

ios - iOS8 中的 UIScrollView 行为不同

ios - 如何根据商店为我的应用程序使用不同的名称

ios - 具有环绕但不滚动的 UIView 的水平列表

ios - 无法将 Parse.com 中存储的 NSData 转换为 NSString?

Java 8 - 使用 BiPredicate 进行过滤