我在SwiftUI中遇到了一些基本的MVVM概念。我很感激这可能是一个简单的问题,但我的大脑很疲惫,我想不通。
这是我的模型/视图/视图模型等
import Foundation
struct Challenges {
var all: [Challenge]
init() {
all = []
}
}
struct Challenge: Identifiable, Codable, Hashable {
private(set) var id = UUID()
private(set) var name: String
private(set) var description: String
private(set) var gpxFile: String
private(set) var travelledDistanceMetres: Double = 0
init(name: String, description: String, gpxFile: String) {
self.name = name
self.description = description
self.gpxFile = gpxFile
}
mutating func addDistance(_ distance: Double) {
travelledDistanceMetres += distance
}
}
import SwiftUI
@main
struct ActivityChallengesApp: App {
var body: some Scene {
WindowGroup {
ChallengesView()
.environmentObject(ChallengesViewModel())
}
}
}
import SwiftUI
class ChallengesViewModel: ObservableObject {
@Published var challenges: Challenges
init() {
challenges = Challenges()
challenges.all = DefaultChallenges.ALL
}
func addDistance(_ distance: Double, to challenge: Challenge) {
challenges.all[challenge].addDistance(distance)
}
}
import SwiftUI
struct ChallengesView: View {
@EnvironmentObject var challengesViewModel: ChallengesViewModel
var body: some View {
NavigationView {
List {
ForEach(challengesViewModel.challenges.all) { challenge in
NavigationLink {
ChallengeView(challenge)
.environmentObject(challengesViewModel)
} label: {
VStack(alignment: .leading) {
Text(challenge.name)
Text("(challenge.travelledDistanceMetres)")
}
}
}
}
.navigationTitle("Challenges")
}
}
}
import SwiftUI
struct ChallengeView: View {
var challenge: Challenge
@EnvironmentObject var challengesViewModel: ChallengesViewModel
init(_ challenge: Challenge) {
self.challenge = challenge
}
var body: some View {
VStack(alignment: .leading) {
Text(challenge.name)
Text("(challenge.travelledDistanceMetres)")
}
.onTapGesture {
handleTap()
}
}
func handleTap() {
challengesViewModel.addDistance(40, to: challenge)
}
}
我理解这些概念,但我对ViewModel应该是什么感到困惑。
我觉得这太过分了,即将模型对象发送到视图,并将视图模型作为环境对象。通过此设置,我从视图中调用视图模型中的addDistance()
函数来更改模型。
ChallengeView(challenge)
.environmentObject(challengesViewModel)
是为集合设置一个视图模型更好,还是为每个模型对象设置一个查看模型更好?
这是我能想到的最简单的版本
我真的不明白挑战的必要性。好吗?所以我把它拿了出来。
我有
- 单个
challenge
的结构 - 发布
challenges
数组的可观察类 - 用
@StateObject
实例化一次,然后像您所做的那样向下传递
btw:结构不需要显式初始化程序
这就是:
@main
struct ActivityChallengesApp: App {
// here you create your model once
@StateObject var challenges = ChallengesModel()
var body: some Scene {
WindowGroup {
ChallengesView()
.environmentObject(challenges)
}
}
}
struct Challenge: Identifiable, Codable, Hashable {
var id = UUID()
var name: String
var description: String
var gpxFile: String
var travelledDistanceMetres: Double = 0
mutating func addDistance(_ distance: Double) {
travelledDistanceMetres += distance
}
}
class ChallengesModel: ObservableObject {
@Published var challenges: [Challenge]
init() {
// Test data
challenges = [
Challenge(name: "Challenge One", description: "?", gpxFile: ""),
Challenge(name: "Challenge Two", description: "?", gpxFile: ""),
Challenge(name: "Last Challenge", description: "?", gpxFile: "")
]
}
func addDistance(_ distance: Double, to challenge: Challenge) {
// find the challenge and update it
if let i = challenges.firstIndex(where: {$0.id == challenge.id}) {
challenges[i].addDistance(distance)
}
}
}
struct ChallengesView: View {
@EnvironmentObject var challengesModel: ChallengesModel
var body: some View {
NavigationView {
List {
ForEach(challengesModel.challenges) { challenge in
NavigationLink {
ChallengeView(challenge: challenge)
.environmentObject(challengesModel)
} label: {
VStack(alignment: .leading) {
Text(challenge.name)
Text("(challenge.travelledDistanceMetres)")
}
}
}
}
.navigationTitle("Challenges")
}
}
}
struct ChallengeView: View {
var challenge: Challenge
@EnvironmentObject var challengesModel: ChallengesModel
var body: some View {
VStack(alignment: .leading) {
Text(challenge.name)
Text("(challenge.travelledDistanceMetres)")
}
.onTapGesture {
handleTap()
}
}
func handleTap() {
challengesModel.addDistance(40, to: challenge)
}
}