gpt4 book ai didi

ios - 使用 RxSwift 时如何在 UITableViewCell 中保留 UITextField 的值?

转载 作者:行者123 更新时间:2023-12-05 02:41:24 25 4
gpt4 key购买 nike

我正在制作一个包含表单的应用程序。我所做的是使用 UITableView 制作包含某些部分的表单。每个单元格都有一个 UITextField 来获取用户的输入。因为我使用的是 RxSwift,所以我将单元格内的每个文本字段绑定(bind)到一个 BehaviorRelay 到我的 ViewModel 类。不幸的是,每当用户向每个单元格输入内容时,它都会有一个非常奇怪的行为。例如(如下所示)每次用户在第一个单元格输入一些值,用户向下滚动后, TableView 中的最后一个单元格具有相同的值(注意用户尚未滚动页面,因此没有向最后一个单元格输入任何值)。第二个例子是当我在最后 3 个单元格中输入一些值时,前 3 个单元格的值也发生了变化。

enter image description here

以下是我设法实现这一目标的方法:

我的自定义单元格类:

class FormTableViewCell: UITableViewCell {

@IBOutlet weak var titleLbl: UILabel!
@IBOutlet weak var valueTf: UITextField!

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

func configureCell(title: String, placeholder: String, keyboardType: UIKeyboardType? = .default) {
titleLbl.text = title
valueTf.placeholder = placeholder
valueTf.keyboardType = keyboardType ?? .default
}

func getValueAsDriver() -> Driver<String> {
valueTf.rx.text.orEmpty.asDriver()
}

}

我如何在我的 UIViewController 类中配置 tableView(_:cellForRowAt:) 函数中的每个单元格(我的应用程序中总共有大约 15 个单元格):

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let formCell = tableView.dequeueReusableCell(withIdentifier: Config.FORM_TABLEVIEWCELL_ID) as! FormTableViewCell
if indexPath.section == 1 {
if indexPath.row == 0 {
formCell.configureCell(title: "Some title", placeholder: "Some placeholder", keyboardType: .decimalPad)
viewModel.bindValue(from: formCell.getValueAsDriver())
return formCell
} else if indexPath.row == 1 {
// Do pretty much the same thing as before
}
} else if indexPath.section == 2 {
// Do pretty much the same thing as before
} ...

return UITableViewCell()
}

我如何在我的 ViewModel 类中绑定(bind)文本字段值:

final class ViewModel {
private let _someValue = BehaviorRelay<String>(value: "")

func bindValue(from driver: Driver<String>) {
driver.distinctUntilChanged().drive(onNext: { [unowned self] value in
_someValue.accept(value)
}).disposed(by: disposeBag)
}
}

我的问题是,当用户滚动表格 View 时,如何将每个文本字段的值保留在单元格内?另外,如果您有更好的方法,请告诉我。谢谢。

最佳答案

您可以通过将文本字段绑定(bind)到行为中继并使用 take(1) 来保留每个文本字段的值。像这样的东西:

viewModel._someValue
.take(1)
.bind(to: valueTf.rx.text)
.disposed(by: cellDisposeBag)

注意上面你的手机需要一个处理袋。在该单元格中,您还必须释放 disposeBag 并在 prepareForReuse 方法中创建一个新的。

override func prepareForReuse() {
super.prepareForReuse()
disposeBag = DisposeBag()
}

一些其他的一般注意事项...如果您觉得有必要在您的 View 模型中放置一个 disposeBag,那么您可能做错了什么。您的 View 模型不应该是一个类。它应该是一个结构或更好的单一函数。


更好的方法是使用 RxDataSources 库并摆脱 View Controller 中巨大的“if/else if”链。我会更像这样写:

final class ExampleViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!
let viewModel = ViewModel()
let disposeBag = DisposeBag()

override func viewDidLoad() {
super.viewDidLoad()

let dataSource = RxTableViewSectionedReloadDataSource<FormSectionModel>(
configureCell: { [formValues = viewModel.formValues] _, tableView, _, item in
let formCell = tableView.dequeueReusableCell(withIdentifier: Config.FORM_TABLEVIEWCELL_ID) as! FormTableViewCell
formCell.configureCell(item: item, formValues: formValues)
return formCell
},
titleForHeaderInSection: { dataSource, index in
dataSource.sectionModels[index].model
}
)

Observable.just(viewModel.form)
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
}
}

final class FormTableViewCell: UITableViewCell {

@IBOutlet weak var titleLbl: UILabel!
@IBOutlet weak var valueTf: UITextField!
var disposeBag = DisposeBag()

override func prepareForReuse() {
super.prepareForReuse()
disposeBag = DisposeBag()
}

func configureCell(item: FormItem, formValues: BehaviorSubject<[FormID : String]>) {
titleLbl.text = item.title
valueTf.placeholder = item.placeholder
valueTf.keyboardType = item.keyboardType

formValues
.map { $0[item.formID] }
.take(1)
.bind(to: valueTf.rx.text)
.disposed(by: disposeBag)

valueTf.rx.text
.withLatestFrom(formValues) { entry, values in
with(values) {
$0[item.formID] = entry ?? ""
}
}
.bind(to: formValues)
.disposed(by: disposeBag)
}
}

struct ViewModel {
let form: [FormSectionModel] = [
FormSectionModel(model: "PELANGGAN", items: [
FormItem(formID: .pelanggan, title: "Pelanggan", placeholder: "")
]),
FormSectionModel(model: "PUNGGUNG", items: [
FormItem(formID: .pangangPunggung, title: "Pangang Punggung", placeholder: "eg 20", keyboardType: .numberPad),
FormItem(formID: .tinggiPunggung, title: "Tinggi Punggung", placeholder: "eg 20", keyboardType: .numberPad)
]),
FormSectionModel(model: "PUNDAK", items: [
FormItem(formID: .jarakPundak, title: "Jarak Pundak", placeholder: "eg 20", keyboardType: .numberPad),
FormItem(formID: .lebarPundak, title: "Lebar Pundak", placeholder: "eg 20", keyboardType: .numberPad),
FormItem(formID: .tinggiPundak, title: "Tinggi Pundak", placeholder: "eg 20", keyboardType: .numberPad),
])
]
let formValues = BehaviorSubject<[FormID: String]>(value: [:])
}

typealias FormSectionModel = SectionModel<String, FormItem>

struct FormItem {
let formID: FormID
let title: String
let placeholder: String
let keyboardType: UIKeyboardType
}

extension FormItem {
init(formID: FormID, title: String, placeholder: String) {
self.formID = formID
self.title = title
self.placeholder = placeholder
self.keyboardType = .default
}
}

enum FormID {
case pelanggan
case pangangPunggung
case tinggiPunggung
case jarakPundak
case lebarPundak
case tinggiPundak
}

func with<T>(_ item: T, _ fn: (inout T) -> Void) -> T {
var item = item
fn(&item)
return item
}

关于ios - 使用 RxSwift 时如何在 UITableViewCell 中保留 UITextField 的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68139983/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com