skip to Main Content

I’m building a WatchOS companion app. In a View there’s a Slider that reads and writes value. This value is being communicated between iOS and WatchOS app.

struct ReadingView: View {

    @EnvironmentObject var watcher: ViewModelWatch
    var body: some View {
        CompactSlider(value: $watcher.sliderValue, in: -1000...1000, step: 50, direction: .center) {
            VStack {
                Text("Compensation")
                Text(String(format: "%.0fK", watcher.sliderValue))
            }
        }
        .onChange(of: watcher.sliderValue) { newValue in
            ViewModelWatch.shared.session.transferUserInfo(["compensationValue": newValue])
        }
        
    }
}

This is how my model looks like:

class ViewModelWatch : NSObject, WCSessionDelegate, ObservableObject {

    static let shared = ViewModelWatch()
    var session: WCSession = .default
    @Published var sliderValue = 0.0
    
    init(session: WCSession = .default){
        self.session = session
        super.init()
        self.session.delegate = self
        session.activate()
    }
    
    func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
        self.sliderValue = userInfo["compensationValue"] as? Double ?? 0.0        
    }
}

Steps and what’s happening:

  1. Ran the apps on both iOS and WatchOS.

  2. Sent "compensationValue" UserInfo from iOS app and received in didReceiveUserInfo in the Watch app, the Slider view in iOS app updates just fine.

  3. Sent "compensationValue" UserInfo from Watch app and received in didReceiveUserInfo in the iOS app, the Slider view in iOS app updates just fine.

Issue:

  1. Now when I repeat the 2nd step i.e., send "compensationValue" UserInfo from iOS app to Watch app, the CompactSlider doesn’t update.

It’s like once @Published var sliderValue = 0.0 is written by CompactSlider, it doesn’t update views when updated by didReceiveUserInfo.

2

Answers


  1. Try to assign value on main queue, like

    func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
        DispatchQueue.main.async {
           self.sliderValue = userInfo["compensationValue"] as? Double ?? 0.0        
        }
    }
    

    or make view model MainActor if deployment target version allows

    @MainActor
    class ViewModelWatch
    
    Login or Signup to reply.
  2. Add private to this line

    private init(session: WCSession = .default){
    

    It will expose if there is an area in your code where you are not using the same instance.

    You should only be using ViewModelWatch.shared so they can share information.

    Another call of ViewModelWatch() will be separate from ViewModelWatch.shared

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search