@Obersvable 类中 var 的值仅在一个视图中更新,而不是在另一个视图中更新

问题描述 投票:0回答:1

我有一个带有 WatchViewModel 的配套 WatchOS 应用程序,它当前保存从应用程序发送的所有变量。我必须查看,每个视图都应该显示另一个变量。在一个视图 (ActivityDistributionView) 中,一切都工作得很好,但在另一个视图 (LeaderboardView) 中,该值是初始值并且不会发生更改。实际上 LeaderboardView 中没有值被更新,但在 ActivityDistributionView 中,所有值都工作正常。

我发现,如果我注释掉 ActivityDistribution 中 ViewModel 的声明,那么我的代码就可以工作。这是否意味着我只能声明该类的工作实例一次?

ContentView body:
var body: some View {
        TabView{
            ScoreTabView(dailyScore: viewModel.scores["score"] ?? 0, postureScore: viewModel.scores["posture"] ?? 0, movementScore: viewModel.scores["movement"] ?? 0)
            
            NavigationStack{
                List{
                    Section("Last message received:"){
                        Text("\(formatDate(date: viewModel.lastMessageTime))").font(.body)
                        //Text("\(viewModel.lastMessage.keys.sorted().formatted())").padding()
                    }
                    NavigationLink("Leaderboard"){
                        LeaderboardViews()
                    }
                    NavigationLink("Activity Distribution"){
                        ActivityDistributionView()
                    }
                }
            }
        }
    }


struct LeaderboardViews: View {
    @State private var viewModel: WatchViewModel = WatchViewModel()
    var body: some View {
        Text("\(viewModel.leaderboardMessage)")
            
    }
}

struct ActivityDistributionView: View {
    @State private var viewModel: WatchViewModel = WatchViewModel()
    @State private var vibrates = false
    let activities = ["sitting", "walking", "standing", "onDesk", "driving", "lying"]

    
    var body: some View {
        NavigationStack{
            ScrollView{
                Text("\(viewModel.leaderboardMessage)")
            }
            .navigationTitle("Acitivity Distribution")
            .navigationBarTitleDisplayMode(.inline)
        }
    }
}

    @Observable
    class WatchViewModel: NSObject{
        var session: WCSession
        
        var activityDistribution: [String: Any] = [:]
        var scores: [String: Double] = [:]
        var leaderboardMessage: LeaderboardMessage = LeaderboardMessage(method: "InitExampleLeaderboardMessage", payload: [:])

        
        //more code
        
    }


    //Sends Data from WatchOS to AppDelegate (to later push to Flutter)
extension WatchViewModel: WCSessionDelegate {
    //code that works
case .LeaderboardMessage:
    self.lastMessage = message["payload"] as! [String : Any]
    
        //message gets converted into JSON
        let messageAsJSON = self.encodeJSONData(encode: message)
        //message gets decoded into the proper struct
        let decodedMessage = self.decodeJSONData(decode: messageAsJSON!) ?? LeaderboardMessage(method: "ExampleLeaderboardData", payload: ["Date" : [ExerciseDataWrapper(name: "Nobody", data: ExerciseData(duration: ExerciseData.Duration(displayString: "/", value: 0), exerciseScore: ExerciseData.ExerciseScore(displayString: "/", value: 0), movement: ExerciseData.Movement(displayString: "/", value: 0), posture: ExerciseData.Posture(displayString: "/", value: 0), postureAboveThresholdDuration: ExerciseData.PostureAboveThresholdDuration(displayString: "/", value: 0), score: ExerciseData.Score(displayString: "/", value: 0)))]])
        //leaderboardMessage gets updated to the last send leaderboardMessage
    self.leaderboardMessage = decodedMessage
    //assigning works but not in the LeaderboardsView()
}


我尝试更改 NavLink 的名称和位置,或尝试将 viewModel 值从 ContentView 传递到 LeaderboardView,但没有成功。

swift mvvm swift-class
1个回答
0
投票

您应该在 ContentView 上有一个实例并从那里将其传递下去。 由于某种原因,当我尝试将其从 ContentView 传递到其他视图时,Swift 决定使用 ActivityView 中声明的 ViewModel-Instance 而不是 ContentView 中声明的 ViewModel-Instance,但它们从未更新。

因此,正确的代码是将 viewModel 放在我的 ContentView 中,并将其从那里传递到我的其他视图。

struct LeaderboardViews: View {
let leaderboardMessage: LeaderboardMessage
var body: some View {
    Text("\(leaderboardMessage.method)")
       
}

}

struct ActivityDistributionView: View {
@State private var vibrates = false
let activities = ["sitting", "walking", "standing", "onDesk", "driving", "lying"]
let activityDistribution: [String: Double]


var body: some View {
    NavigationStack{
        /*ForEach(viewModel.leaderboardData.keys.sorted(), id: \.self) { day in
            Text("Day: \(viewModel.leaderboardData[day] ?? "No Date")")
        }*/
        ScrollView{
            //code
        }
        .navigationTitle("Acitivity Distribution")
        .navigationBarTitleDisplayMode(.inline)
    }
}

}

struct ContentView: View {
@State private var viewModel: WatchViewModel = WatchViewModel()
@State private var vibrates = false
let activities = ["sitting", "walking", "standing", "onDesk"]
var body: some View {
    TabView{
        ScoreTabView(dailyScore: viewModel.scores["score"] ?? 0, postureScore: viewModel.scores["posture"] ?? 0, movementScore: viewModel.scores["movement"] ?? 0)
        
        NavigationStack{
            List{
                Section("Last message received:"){
                    Text("\(formatDate(date: viewModel.lastMessageTime))").font(.body)
                    //Text("\(viewModel.lastMessage.keys.sorted().formatted())").padding()
                }
                NavigationLink("Leaderboard"){
                    LeaderboardViews(leaderboardMessage: viewModel.leaderboardMessage)
                }
                NavigationLink("Activity Distribution"){
                    ActivityDistributionView( activityDistribution: viewModel.activityDistribution as! [String: Double])
                }
            }
        }
    }
}

}

© www.soinside.com 2019 - 2024. All rights reserved.