2 Replies
      Latest reply on Nov 10, 2019 9:14 AM by eos-pi
      eos-pi Level 1 Level 1 (0 points)

        I'm using WatchConnectivity and the WCSessionDelegate to successfully receive user info from my iOS app to my watchOS extension. When new data is received, I want to update my SwiftUI view with the latest information. I have an @ObservedObject property in the HostingController which is set to the latest data when it arrives. However, this does not trigger a UI update. How can I fix this? I've posted the code below. Thank you!

         

        import WatchKit
        import SwiftUI
        import WatchConnectivity
        import Combine
        
        class UserData: ObservableObject {
            @Published var account: Account = Account.getCurrentAccount()
        }
        
        class HostingController: WKHostingController<ContentView>, WCSessionDelegate  {
            @ObservedObject private var userData: UserData = UserData()
                
            override init() {
                super.init()
                
                if WCSession.isSupported() {
                    print("WCSession supported")
                    let session = WCSession.default
                    session.delegate = self
                    session.activate()
                }
            }
            
            override var body: ContentView {
                return ContentView(userData: userData)
            }
            
            func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
                
            }
            
            func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
                guard let accountJSON = userInfo["main-account"] as? String else { return }
                
                let userDefaults = UserDefaults()
                userDefaults.set(accountJSON, forKey: "main-account")
                
                self.userData.account = Account.getCurrentAccount()
        
                print("\n\nReceived this: \(accountJSON) \n\n")
            }
        }
        
        • Re: Update SwiftUI view with data received from WatchConnectivity
          Jim Dovey Level 3 Level 3 (130 points)

          There are a couple of things you can do here.

           

          First of all, you don't show what ContentView looks like. That's the view that needs to be updated, so that's what needs to use the @ObservedObject property wrapper. Note that WKHostingController is not a View, so SwiftUI isn't going to do anything automatically based on changes to its content. The ContentView, though, is a View, so if that contains an @ObservedObject property then everything ought to work.

           

          The second option may be the better, though. Look at the interface definition for WKHostingController:

           

          open class WKHostingController<Body> : WKInterfaceController where Body : View {
          
              /// The root `View` of the view hierarchy to display.
              open var body: Body { get }
          
              /// Invalidates the current `body` and triggers a body update during the
              /// next update cycle.
              public func setNeedsBodyUpdate()
          
              /// Update `body` immediately, if updates are pending.
              public func updateBodyIfNeeded()
          
              @objc override dynamic public init()
          }
          

           

          There's a method there called setNeedsBodyUpdate() which ought to do exactly what you need. Simply add a call to self.setNeedsBodyUpdate() inside your session(_:didReceiveUserInfo:) implementation, for instance at line 39 of your example, and you should see everything update properly.