iosswiftswift3watchconnectivitywcsession

App crashes when sending message to Apple Watch


I have a UIButton action (sendMessageToWatch) in iOS app and a label (messageLabel) in Apple Watch. What I want to do is be able to tap the button in the iPhone and see it in the label in the Apple Watch.

For some reason when I tap the button the app crashes without outputting any error.

What am I missing?

Here is the code.

iOS ViewController

import UIKit
import WatchConnectivity

class ViewController: UIViewController, WCSessionDelegate {
    
    var session: WCSession!

    override func viewDidLoad() {
        super.viewDidLoad()
        if WCSession.isSupported() {
            let session = WCSession.default()
            session.delegate = self
            session.activate()
        }
    }
    
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
    func sessionDidDeactivate(_ session: WCSession) { }
    func sessionDidBecomeInactive(_ session: WCSession) { }
    
    @IBAction func sendMessageToWatch(_ sender: Any) {
        //Send Message to Watch
        let messageToSend:Dictionary = ["messageFromPhone":"Hello Watch."]
        
        session.sendMessage(messageToSend, replyHandler: { replyMessage in
            // some replay
        }, errorHandler: {error in
            // catch any errors here
        })
    }

}

Watch InterfaceController

import WatchKit
import Foundation
import WatchConnectivity

class InterfaceController: WKInterfaceController, WCSessionDelegate {
    
    var session: WCSession!
    @IBOutlet var messageLabel: WKInterfaceLabel!

    func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
        //handle received message
        let value = message["messageFromPhone"] as? String
        DispatchQueue.main.async {
            self.messageLabel.setText(value)
        }
    }
    
    override func awake(withContext context: Any?) {
        super.awake(withContext: context)
    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
        
        if (WCSession.isSupported()) {
            session = WCSession.default()
            session.delegate = self
            session.activate()
        }
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate()
    }
    
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
}

Solution

  • You are declaring another session object inside viewDidLoad redeclaring it with let. Just remove it:

    var session: WCSession!
    override func viewDidLoad() {
        super.viewDidLoad()
        if WCSession.isSupported() {
            session = WCSession.default()
            session.delegate = self
            session.activate()
        }
    }