Я хочу отображать несколько текстовых полей, представляющих счет каждой части матча.
Пример: для волейбольного матча у нас есть 25/20, 25/22, 25/23. Глобальная оценка - 3/0.
Архитектура глобальных компонентов:
>> ParentComponent
>> MainComponent
>> X TextFieldsComponent (2 text fields, home/visitor score)
Самый низкий компонент, TextFieldsComponent, содержит базовые c привязки:
struct TextFieldsComponent: View {
@ObservedObject var model: Model
class Model: ObservableObject, Identifiable, CustomStringConvertible {
let id: String
@Published var firstScore: String
@Published var secondScore: String
var description: String {
"\(firstScore) \(secondScore)"
}
init(id: String, firstScore: String = .empty, secondScore: String = .empty) {
self.id = id
self.firstScore = firstScore
self.secondScore = secondScore
}
}
var body: some View {
HStack {
TextField("Dom.", text: $model.firstScore)
.keyboardType(.numberPad)
TextField("Ext.", text: $model.secondScore)
.keyboardType(.numberPad)
}
}
}
Родительский компонент должен отображать общий счет всех частей матча. И я хотел попробовать привязку / поток Combine, чтобы получить общий балл.
Я пробовал несколько решений, и в итоге я получил этот нерабочий код (сокращение, похоже, не берет все элементы массива, но внутренне сохраняет предыдущий результат):
struct MainComponent: View {
@ObservedObject var model: Model
@ObservedObject private var totalScoreModel: TotalScoreModel
class Model: ObservableObject {
@Published var scores: [TextFieldsComponent.Model]
init(scores: [TextFieldsComponent.Model] = [TextFieldsComponent.Model(id: "main")]) {
self.scores = scores
}
}
private final class TotalScoreModel: ObservableObject {
@Published var totalScore: String = ""
private var cancellable: AnyCancellable?
init(publisher: AnyPublisher<String, Never>) {
cancellable = publisher.print().sink {
self.totalScore = $0
}
}
}
init(model: Model) {
self.model = model
totalScoreModel = TotalScoreModel(
publisher: Publishers.MergeMany(
model.scores.map {
Publishers.CombineLatest($0.$firstScore, $0.$secondScore)
.map { ($0.0, $0.1) }
.eraseToAnyPublisher()
}
)
.reduce((0, 0), { previous, next in
guard let first = Int(next.0), let second = Int(next.1) else { return previous }
return (
previous.0 + (first == second ? 0 : (first > second ? 1 : 0)),
previous.1 + (first == second ? 0 : (first > second ? 0 : 1))
)
})
.map { "[\($0.0)] - [\($0.1)]" }
.eraseToAnyPublisher()
)
}
var body: some View {
VStack {
Text(totalScoreModel.totalScore)
ForEach(model.scores) { score in
TextFieldsComponent(model: score)
}
}
}
}
Я ищу решение, чтобы получать событие при каждом изменении привязки и объединять его в один поток, чтобы отобразить его в MainComponent.
Н / Б: компонент TextFieldsComponent также должен использоваться автономно.