#swiftui
Вопрос:
На самом деле я только начинаю работать со SwiftUI и пытаюсь разобраться в MVVM.
Приведенный ниже код отображает высоту и 4 кнопки переключения, до сих пор я подключил только 2.
Майор вверх и майор вниз.
При нажатии я вижу в консоли, что значение изменяется, как и ожидалось.
Чего я не вижу, так это обновления основного дисплея, отражающего изменения.
Я попытался провести рефакторинг своего кода, чтобы включить модель представления в каждую структуру, но все еще не вижу изменений.
Я думаю, что я рассмотрел основы, но я в тупике, сейчас я использую один файл, но планирую переместить модель и модель представления в отдельные файлы, когда у меня будет рабочий макет.
Спасибо, что посмотрели.
import SwiftUI
/// This is our "ViewModel"
class setHeightViewModel: ObservableObject {
struct ImperialAndMetric {
var feet = 16
var inches = 3
var meters = 4
var CM = 95
var isMetric = true
}
// The model should be Private?
// ToDo: Fix the private issue.
@Published var model = ImperialAndMetric()
// Our getters for the model
var feet: Int { return model.feet }
var inches: Int { return model.inches }
var meters: Int { return model.meters }
var cm: Int { return model.CM }
var isMetric: Bool { return model.isMetric }
/// Depending upon the selected mode, move the major unit up by one.
func majorUp() {
if isMetric == true {
model.meters = 1
print("Meters is now: (meters)")
} else {
model.feet = 1
print("Feet is now: (feet)")
}
}
/// Depending upon the selected mode, move the major unit down by one.
func majorDown() {
if isMetric == true {
model.meters -= 1
print("Meters is now: (meters)")
} else {
model.feet -= 1
print("Feet is now: (feet)")
}
}
/// Toggle the state of the display mode.
func toggleMode() {
model.isMetric = !isMetric
}
}
// This is our View
struct ViewSetHeight: View {
// UI will watch for changes for setHeihtVM now.
@ObservedObject var setHeightVM = setHeightViewModel()
var body: some View {
NavigationView {
Form {
ModeArea(viewModel: setHeightVM)
SelectionUp(viewModel: setHeightVM)
// Show the correct height format
if self.setHeightVM.isMetric == true {
ValueRowMetric(viewModel: self.setHeightVM)
} else {
ValueRowImperial(viewModel: self.setHeightVM)
}
SelectionDown(viewModel: setHeightVM)
}.navigationTitle("Set the height")
}
}
}
struct ModeArea: View {
var viewModel: setHeightViewModel
var body: some View {
Section {
if viewModel.isMetric == true {
SwitchImperial(viewModel: viewModel)
} else {
SwitchMetric(viewModel: viewModel)
}
}
}
}
struct SwitchImperial: View {
var viewModel: setHeightViewModel
var body: some View {
HStack {
Button(action: {
print("Imperial Tapped")
}, label: {
Text("Imperial").onTapGesture {
viewModel.toggleMode()
}
})
Spacer()
Text("(viewModel.feet)'-(viewModel.inches)"").foregroundColor(.gray)
}
}
}
struct SwitchMetric: View {
var viewModel: setHeightViewModel
var body: some View {
HStack {
Button(action: {
print("Metric Tapped")
}, label: {
Text("Metric").onTapGesture {
viewModel.toggleMode()
}
})
Spacer()
Text("(viewModel.meters).(viewModel.cm) m").foregroundColor(.gray)
}
}
}
struct SelectionUp: View {
var viewModel: setHeightViewModel
var body: some View {
Section {
HStack {
Button(action: {
print("Major Up Tapped")
viewModel.majorUp()
}, label: {
Image(systemName: "chevron.up").padding()
})
Spacer()
Button(action: {
print("Minor Up Tapped")
}, label: {
Image(systemName: "chevron.up").padding()
})
}
}
}
}
struct ValueRowImperial: View {
var viewModel: setHeightViewModel
var body: some View {
HStack {
Spacer()
Text(String(viewModel.feet)).accessibility(label: Text("Feet"))
Text("'").foregroundColor(Color.gray).padding(.horizontal, -10.0).padding(.top, -15.0)
Text("-").foregroundColor(Color.gray).padding(.horizontal, -10.0)
Text(String(viewModel.inches)).accessibility(label: Text("Inches"))
Text(""").foregroundColor(Color.gray).padding(.horizontal, -10.0).padding(.top, -15.0)
Spacer()
}.font(.largeTitle).padding(.zero)
}
}
struct ValueRowMetric: View {
var viewModel: setHeightViewModel
var body: some View {
HStack {
Spacer()
Text(String(viewModel.meters)).accessibility(label: Text("Meter"))
Text(".").padding(.horizontal, -5.0).padding(.top, -15.0)
Text(String(viewModel.cm)).accessibility(label: Text("CM"))
Text("m").padding(.horizontal, -5.0).padding(.top, -15.0).font(.body)
Spacer()
}.font(.largeTitle)
}
}
struct SelectionDown: View {
var viewModel: setHeightViewModel
var body: some View {
Section {
HStack {
Button(action: {
print("Major Down Tapped")
viewModel.majorDown()
}, label: {
Image(systemName: "chevron.down").padding()
})
Spacer()
Button(action: {
print("Minor Down Tapped")
}, label: {
Image(systemName: "chevron.down").padding()
})
}
}
}
}
Комментарии:
1. Так много кода…
model
это опубликованное свойство, так что это то, что вы должны использовать в своем представлении, а не вычисляемые свойства2. Спасибо за ваш ответ, если я попытаюсь получить доступ к модели напрямую в valueRowMetric, это не входит в область применения. Вот почему я передаю модель представления.
3. @JoakimDanielson: Но для вычисляемых свойств нет проблем, они просто будут работать как обычно
4. Я не имел в виду, что вы должны получить к нему прямой доступ. Я имел в виду, что вы должны использовать его при доступе к свойствам, например
viewModel.model.feet
, но опять же, как уже упоминалось, это может быть не проблемой.
Ответ №1:
В тот момент, когда вы получаете setHeightViewModel
в различных представлениях как var, вы должны получить его как an ObservedObject
.
Я предлагаю вам попробовать это, в ViewSetHeight
@StateObject var setHeightVM = setHeightViewModel()
и во всех других ваших представлениях, где вы передаете эту модель, используйте:
@ObservedObject var viewModel: setHeightViewModel
например, в ModeArea
, SwitchImperial
, SwitchMetric
SelectionUp
, и т. Д…
В качестве альтернативы вы могли бы использовать @EnvironmentObject
… чтобы передать setHeightViewModel
всем взглядам, которые в этом нуждаются.
Комментарии:
1. Круто, что это работает, я думаю, мне удалось запутаться, я хотел попытаться сделать структуры как можно меньше, разбив код на более мелкие фрагменты, но, похоже, не смог сделать наблюдаемый объект доступным так далеко в дереве представлений.