Ios 只有一个开关接通
我正在努力应对以下挑战。我用包含开关的自定义单元格创建了表视图。我希望只有一个开关可以打开,例如,在启动后,我打开了第三个开关,然后打开了第七个开关,因此第三个开关关闭,依此类推。我对手机使用rx+协议,不知道如何确定切换了哪个交换机。以前我打算使用过滤器或映射在数据源数组中查找哪个开关打开并以某种方式处理这个问题,但现在我把它搞糟了。我不确定不使用表视图委托方法是否可行。非常感谢,希望有人能解释我错在哪里 //我的手机是这样的: //CellViewModel实现Ios 只有一个开关接通,ios,swift,functional-programming,switch-statement,rx-swift,Ios,Swift,Functional Programming,Switch Statement,Rx Swift,我正在努力应对以下挑战。我用包含开关的自定义单元格创建了表视图。我希望只有一个开关可以打开,例如,在启动后,我打开了第三个开关,然后打开了第七个开关,因此第三个开关关闭,依此类推。我对手机使用rx+协议,不知道如何确定切换了哪个交换机。以前我打算使用过滤器或映射在数据源数组中查找哪个开关打开并以某种方式处理这个问题,但现在我把它搞糟了。我不确定不使用表视图委托方法是否可行。非常感谢,希望有人能解释我错在哪里 //我的手机是这样的: //CellViewModel实现 import Fou
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() {
}
}
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)
}
}
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() {
}
}
//TableViewController实现
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() {
}
}
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)
}
}
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() {
}
}
导入UIKit
导入RxSwift
进口RxCocoa
类TableViewController:UITableViewController{
私有变量数据源:[CellViewModelProtocol]=[]
var vm=TableViewControllerVM()
重写func viewDidLoad(){
super.viewDidLoad()
self.tableView.estimateDroweight=70
self.tableView.rowHeight=UITableView.automaticDimension
self.bindUI()
}
私有func bindUI(){
observeOn(MainScheduler.asyncInstance).bind{[weak self](数据源)在
self?.dataSource=数据源
self?.tableView.reloadData()
}.处理(由:vm.bag)
}
//标记:-表视图数据源
重写func numberOfSections(在tableView:UITableView中)->Int{
返回1
}
重写func tableView(tableView:UITableView,numberofrowsinssection:Int)->Int{
返回self.dataSource.count
}
重写func tableView(tableView:UITableView,cellForRowAt indexath:indexPath)->UITableViewCell{
让cell=tableView.dequeueReusableCell(带标识符:cell.identifier,for:indexPath)作为!cell
如果cell.vm==nil{
cell.vm=CellVM()
}
返回单元
}
}
类TableViewControllerVM:ViewModel{
var数据源:BehaviorSubject=BehaviorSubject(值:[])
let internalBag=DisposeBag()
重写init(){
super.init()
dataSource.onNext(createDataSourceOf(大小:7))
self.handleState()
}
private func createDataSourceOf(大小:Int)->[CellViewModelProtocol]{
var arr:[CellViewModelProtocol]=[]
对于0..中的uuu,此代码可能会帮助您:
扩展TableViewController{
//从viewDidLoad调用
func bind(){
让cells=(0..有一个类似的UI,所以在本地测试并且可以工作。但是代码不是很整洁
ProfileCellViewModel
struct ProfileCellViewModel {
// IMPORTANT!!!
var bibindRelay: BehaviorRelay<Bool>?
}
struct ProfileCellViewModel{
//重要的!!!
var bibindRelay:行为继电器?
}
轮廓细胞
final class ProfileCell: TableViewCell {
@IBOutlet weak var topLabel: Label!
@IBOutlet weak var centerLabel: Label!
@IBOutlet weak var bottomLabel: Label!
@IBOutlet weak var onSwitch: Switch!
public var vm: ProfileCellViewModel? {
didSet {
// IMPORTANT!!!
if let behaviorRelay = vm?.bibindRelay {
(onSwitch.rx.controlProperty(editingEvents: .valueChanged,
getter: { $0.isOn }) { $0.isOn = $1 } <-> behaviorRelay)
.disposed(by: self.rx.reuseBag)
}
}
}
}
最终类ProfileCell:TableViewCell{
@IBVAR topLabel:标签!
@IBVAR中心标签:标签!
@IBVAR底部标签:标签!
@IBOUTLE弱无功开关:开关!
公共var vm:ProfileCellViewModel{
迪塞特{
//重要的!!!
如果let behaviorRelay=vm?.bibindRelay{
(onSwitch.rx.controlProperty(编辑事件:.valueChanged,
getter:{$0.isOn}{$0.isOn=$1}行为延迟)
.处置(由:self.rx.reuseBag)
}
}
}
}
ProfileViewModel
final class ProfileViewModel: ViewModel, ViewModelType {
struct Input {
let loadUserProfileStarted: BehaviorRelay<Void>
}
struct Output {
let userItems: BehaviorRelay<[ProfileCellViewModel]>
let chatRelay: BehaviorRelay<Bool>
let callRelay: BehaviorRelay<Bool>
}
let input = Input(loadUserProfileStarted: BehaviorRelay<Void>(value: ()))
let output = Output(userItems: BehaviorRelay<[ProfileCellViewModel]>(value: []),
chatRelay: BehaviorRelay<Bool>(value: false),
callRelay: BehaviorRelay<Bool>(value:false))
override init() {
super.init()
// IMPORTANT!!!
Observable.combineLatest(output.chatRelay,output.callRelay).pairwise().map { (arg0) -> Int in
let (pre, curr) = arg0
let preFlag = [pre.0,pre.1].filter { $0 == true }.count == 1
let currFlag = [curr.0,curr.1].filter { $0 == true }.count == 2
if preFlag && currFlag {
return [pre.0,pre.1].firstIndex(of: true) ?? 0
}
return -1
}.filter {$0 >= 0}.subscribe(onNext: { (value) in
[self.output.chatRelay,self.output.callRelay][value].accept(false)
}).disposed(by: disposeBag)
}
private func createProfileCellItems(user: User) -> [ProfileCellViewModel] {
// IMPORTANT!!!
let chatCellViewModel = ProfileCellViewModel(topText: nil,
centerText: R.string.i18n.chat(),
bottomText: nil,
switchStatus: true,
bibindRelay: output.chatRelay)
// IMPORTANT!!!
let callCellViewModel = ProfileCellViewModel(topText: nil,
centerText: R.string.i18n.call(),
bottomText: nil,
switchStatus: true,
bibindRelay: output.callRelay)
return [roleCellViewModel,
teamCellViewModel,
statusCellViewModel,
sinceCellViewModel,
chatCellViewModel,
callCellViewModel]
}
}
final类ProfileViewModel:ViewModel,ViewModelType{
结构输入{
让loadUserProfileStarted:BehaviorRelay
}
结构输出{
让userItems:BehaviorRelay
让我们来谈谈:行为与关系
让呼叫中继:行为中继
}
让输入=输入(loadUserProfileStarted:BehaviorRelay(值:())
让输出=输出(userItems:BehaviorRelay(值:[]),
chatRelay:BehaviorRelay(值:false),
callRelay:BehaviorRelay(值:false))
重写init(){
super.init()
//重要的!!!
Observable.CombineTest(output.chatRelay,output.callRelay).pairwise().map{(arg0)->Int in
let(前,当前)=arg0
让preFlag=[pre.0,pre.1]。筛选器{$0==true}。计数==1
设currFlag=[curr.0,curr.1]。筛选器{$0==true}。计数==2
if preFlag&&currFlag{
返回[pre.0,pre.1]。第一个索引(of:true)??0
}
返回-1
}.filter{$0>=0}.subscribe(onNext:{(value)在
[self.output.chatRelay,self.output.callRelay][value]。接受(false)
}).处置(由:处置人)
}
private func createProfileCellItems(用户:用户)->[ProfileCellViewModel]{
//重要的!!!
让chatCellViewModel=ProfileCellViewModel(topText:nil,
centerText:R.string.i18n.chat(),
正文:无,
状态:正确,
bibindRelay:output.chatRelay)
//重要的!!!
让callCellViewModel=ProfileCellViewModel(topText:nil,
centerText:R.string.i18n.call(),
正文:无,
状态:正确,
bibindRelay:output.callRelay)
返回[roleCellViewModel,
teamCellViewModel,
statusCellViewModel,
因为CellViewModel,
chatCellViewModel,
callCellViewModel]
}
}
我用//IMPORTANT!!!
标记了您应该注意的代码。请看一下相同问题的答案,只需使用SwiftUI和Combine。您应该能够使用相同的想法,只需将其翻译成RxSwift和UIKit。非常感谢@DávidPásztor!您可以删除不相关的代码