Search code examples
swiftuiwatchkitapple-watch

Is there a way to create a new session of WKExtendedRuntimeSession in SwiftUI?


I've created a simple countdown timer in watchOS. When you press start the timer starts and session.start is declared as well. Everything works fine in the background. Then when it stops either by the button or by the timer the session will invalidate.

By the way that I'm reading the documentation here

It states, "you can only schedule one session at a time; if you need to reschedule a session, invalidate the current session, and schedule a new one."

So my question is, how do I create a new session in SwiftUI? Here is my code:

import SwiftUI

struct TestView: View {
    @State var start = false
    @State var number = 10
    @State var time = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    var session = WKExtendedRuntimeSession()
    var body: some View {
        VStack {
            Text("\(number)")
            Spacer()
            Button(action: {
                self.start.toggle()
                if self.start {
                    session.start()
                } else {
                    session.invalidate()
                }
            }) {
                Text(self.start ? "Stop" : "Start")
            }
        }.onReceive(self.time) { (_) in
            if self.start {
                if number > 0 {
                    number -= 1
                } else {
                    self.start.toggle()
                    number = 10
                    session.invalidate()
                }
      }
        
    }
    
}
}

Solution

  • It is better to do in class, like Coordinator

    class SessionCoordinator {
        private var session: WKExtendedRuntimeSession?
    
        func start() {
            guard session?.state != .running else { return }
    
            // create or recreate session if needed
            if nil == session || session?.state == .invalid {
                session = WKExtendedRuntimeSession()
            }
            session?.start()
        }
    
        func invalidate() {
            session?.invalidate()
        }
    }
    
    struct TestView: View {
        let coordinator = SessionCoordinator()
        @State var start = false
        @State var number = 10
        @State var time = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
        var body: some View {
            VStack {
                Text("\(number)")
                Spacer()
                Button(action: {
                    self.start.toggle()
                    if self.start {
                        coordinator.start()
                    } else {
                        coordinator.invalidate()
                    }
                }) {
                    Text(self.start ? "Stop" : "Start")
                }
            }.onReceive(self.time) { (_) in
                if self.start {
                    if number > 0 {
                        number -= 1
                    } else {
                        self.start.toggle()
                        number = 10
                        coordinator.invalidate()
                    }
                }
    
            }
    
        }
    }