0

複数の子ビュー モデルを持つビュー モデルがあります。私はwatchOS、SwiftUI、およびCombineにかなり慣れていません-この機会に学びましょう。

私はそれがあるwatchUIを持っています

  1. 再生ボタン (ビュー) -SetTimerPlayPauseButton
  2. 時刻を表示するテキスト (ビュー) -TimerText
  3. ビュー モデル - 1 WatchDayProgramViewModel- N: ExerciseTestClass- N:を持つSetInformationTestClass。各エクササイズ セットには があり、watchTimer & watchTimerSubscription残りの休憩時間を更新するためにタイマーを実行することができました。
  4. ContentView - ViewModel として注入されたものEnvironmentObject

タップSetTimerPlayPauseButtonしてタイマーを開始すると、タイマーが実行され、動作し、remainingRestTime(子ビュー モデル内のプロパティSetInformationTestClass) が正しく変更されますが、更新/変更はTimerTextViewに「公開」されません。

すべてではないにしても、ほとんどの推奨事項を他のSOの回答行いましWatchDayProgramViewModelExerciseTestClassSetInformationTestClass@Published.

ここに画像の説明を入力

私のコードを見直して、それを改善する方法についてアドバイスをください。

コンテンツ ビュー

struct ContentView: View {
    @State var selectedTab = 0
    @StateObject var watchDayProgramVM = WatchDayProgramViewModel()
    
    var body: some View {
        
        TabView(selection: $selectedTab) {
            
            SetRestDetailView().id(2)
    
        }
        .environmentObject(watchDayProgramVM)
        .tabViewStyle(PageTabViewStyle())
        .indexViewStyle(.page(backgroundDisplayMode: .automatic))
        
    }
}

    
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView(watchDayProgramVM: WatchDayProgramViewModel())
        }
    }
}

SetRestDetailView

import Foundation
import SwiftUI
import Combine

struct SetRestDetailView: View {
    
    @EnvironmentObject var watchDayProgramVM: WatchDayProgramViewModel
    
    var setCurrentHeartRate: Int = 120
    @State var showingLog = false
    
    
    var body: some View {


                    HStack {
         
                        let elapsedRestTime = watchDayProgramVM.exerciseVMList[0].sets[2].elapsedRestTime
                        let totalRestTime = watchDayProgramVM.exerciseVMList[0].sets[2].totalRestTime
                        
                        TimerText(elapsedRestTime: elapsedRestTime, totalRestTime: totalRestTime, rect: rect)
                            .border(Color.yellow)

                    }
                    
                    HStack {
                        
                        SetTimerPlayPauseButton(isSetTimerRunningFlag: false,
                                                playImage: "play.fill",
                                                pauseImage: "pause.fill",
                                                bgColor: Color.clear,
                                                fgColor: Color.white.opacity(0.5),
                                                rect: rect) {
                            
                            print("playtimer button tapped")
                            self.watchDayProgramVM.exerciseVMList[0].sets[2].startTimer()
                            
                            
                            let elapsedRestTime = watchDayProgramVM.exerciseVMList[0].sets[2].elapsedRestTime
                            let totalRestTime = watchDayProgramVM.exerciseVMList[0].sets[2].totalRestTime
                            print("printing elapsedRestTime from SetRestDetailView \(elapsedRestTime)")
                            print("printing elapsedRestTime from SetRestDetailView \(totalRestTime)")
                            
                        }
                            .border(Color.yellow)

                    }

 }

}

タイマーテキスト

struct TimerText: View {
    var elapsedRestTime: Int
    var totalRestTime: Int
    var rect: CGRect
    
    var body: some View {
        VStack {
            Text(counterToMinutes())
                .font(.system(size: 100, weight: .semibold, design: .rounded))
                .kerning(0)
                .fontWeight(.semibold)
                .minimumScaleFactor(0.25)
                .padding(-1)
        }
    }
    
    func counterToMinutes() -> String {
        let currentTime = totalRestTime - elapsedRestTime
        let seconds = currentTime % 60
        let minutes = Int(currentTime / 60)
        
        if currentTime > 0 {
            return String(format: "%02d:%02d", minutes, seconds)
        }
        
        else {
            return ""
        }
    }
}

ビューモデル

import Combine

final class WatchDayProgramViewModel: ObservableObject {
    
    @Published var exerciseVMList: [ExerciseTestClass] = [
 (static/hard-coded values for testing)
]

class ExerciseTestClass: ObservableObject {
    
    init(exercise: String, sets: [SetInformationTestClass]) {
        
        self.exercise = exercise
        self.sets = sets
        
    }
    
        var exercise: String
        @Published var sets: [SetInformationTestClass]
    
    }

class SetInformationTestClass: ObservableObject {
    
    init(totalRestTime: Int, elapsedRestTime: Int, remainingRestTime: Int, isTimerRunning: Bool) {
        
        self.totalRestTime = totalRestTime
        self.elapsedRestTime = elapsedRestTime
        self.remainingRestTime = remainingRestTime
        self.isTimerRunning = isTimerRunning
        
    }
    
    @Published var totalRestTime: Int
    @Published var elapsedRestTime: Int
    @Published var remainingRestTime: Int
    
    @Published var isTimerRunning = false
    @Published var watchTimer = Timer.publish(every: 1.0, on: .main, in: .default)
    @Published var watchTimerSubscription: AnyCancellable? = nil
    
    @Published private var startTime: Date? = nil
    
    
    func startTimer() {
        
        print("startTimer initiated")
        self.watchTimerSubscription?.cancel()
        
        if startTime == nil {
            startTime = Date()
        }
        
        self.isTimerRunning = true
        
        self.watchTimerSubscription = watchTimer
            .autoconnect()
            .sink(receiveValue: { [weak self] _ in
                
                guard let self = self, let startTime = self.startTime else { return }
                
                let now = Date()
                let elapsedTime = now.timeIntervalSince(startTime)
                
                self.remainingRestTime = self.totalRestTime - Int(elapsedTime)
                
                self.elapsedRestTime = self.totalRestTime - self.remainingRestTime
                                                    
                guard self.remainingRestTime > 0 else {
                        self.pauseTimer()
                        return
                    }

self.objectWillChange.send()
                
                print("printing elapsedRest Time \(self.elapsedRestTime) sec")
                print("printing remaining Rest time\(self.remainingRestTime)sec ")
                
            })
    }
    
    func pauseTimer() {
        //stop timer and retain elapsed rest time
        
        print("pauseTimer initiated")
        self.watchTimerSubscription?.cancel()
        self.watchTimerSubscription = nil
        self.isTimerRunning = false
        self.startTime = nil
        
    }
    
        
4

1 に答える 1