0

I am facing an issue trying to convert message from apple watch's WC session [String: Any] as I am customizing a sample project that retrieves heart rate from apple watch and send it to iPhone. I am hoping that I can get some help as I am already struggling with watchconnectivity for 3 days.

I do see that I am receiving the message properly from Apple Watch and I am close to utilize the message received to update heart rate at iOS app side. But I think the "guard let" statement is causing the didReceiveMessage function to stop half way.

I am not sure, but I think if I can "unwrap" the message ["rate": 61] into 61 in double format, I should be able to pass the guard let function and get this function working.

enter image description here

enter image description here

On top of that I am seeing another error saying "NO with WCErrorCodeDeliveryFailed", but I am not sure why this is being populated as I already implemented suggested solutions from other SO answers. But I think this error is redundant/unrelated to above error message.

enter image description here

Would appreciate help.

import Foundation
import WatchConnectivity

protocol WatchKitConnectionDelegate: AnyObject {
    func didFinishedActiveSession()
    func updateLatestHeartRate(_ LatestHeartRate: Double)
}

protocol WatchKitConnectionProtocol {
    func startSession()
    func sendMessage(message: [String : AnyObject], replyHandler: (([String : AnyObject]) -> Void)?, errorHandler: ((NSError) -> Void)?)
}

class WatchKitConnection: NSObject {
    static let shared = WatchKitConnection()
    weak var delegate: WatchKitConnectionDelegate?
    
    private override init() {
        super.init()
    }
    
    func sendHeartRate(rate: Int) {
        WCSession.default.sendMessage(["rate": rate], replyHandler: nil) { error in
            print("Failed to send message: \(error)")
        }

        print("from iOS watchkit connection")
    }

extension WatchKitConnection: WatchKitConnectionProtocol {
    func startSession() {
        session?.delegate = self
        session?.activate()
    }
    
    func sendMessage(message: [String : AnyObject],
                     replyHandler: (([String : AnyObject]) -> Void)? = nil,
                     errorHandler: ((NSError) -> Void)? = nil)
    
    {
        validReachableSession?.sendMessage(message, replyHandler: { (result) in
            print(result)
            print("success in phone sendmessage function")
        }, errorHandler: { (error) in
            print("error in phone sendmessage function")
            print(error)
        })
    }
    
}

extension WatchKitConnection: WCSessionDelegate {

func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
        print("didReceiveMessage from watch")
        print(message)
        
        delegate?.updateLatestHeartRate(Double(message.values.first))
        
        guard let heartRate = message.values.first as? String? else {
            return
        }
        guard let heartRateDouble = Double(heartRate!) else {
            return
        }
        
        print("printing heartRate double from message\(heartRateDouble)")
        
        delegate?.updateLatestHeartRate(heartRateDouble)
        
        print("updateLatestHeartRate")
      }

WatchKitConnection Swift file at iOS App

Michael
  • 370
  • 3
  • 11
  • 1
    Yes, you need to safely unwrap your optional value. You're trying to use `message.values.first` before you unwrap it on the next line. Unwrap first, then pass it to your delegate method. – Rob Nov 30 '21 at 16:28
  • 1
    Also, is `message.value.first` really a `String`? Or is it an `Int`? And if it is a string, you've got an extra `?` in there, e.g., it should be `guard let heartRate = message.values.first as? String else { ... }` (note, not `String?`). – Rob Nov 30 '21 at 16:28
  • thanks for your feedback, let me try, and the message is ["rate": 61] so it's an Int. – Michael Nov 30 '21 at 16:31
  • 1
    Be careful assuming it's an `Int` on the basis of the print statement. But if it was an integer, then it’s `guard let heartRate = message.values.first as? Int else { ... }`. – Rob Nov 30 '21 at 16:32
  • 1
    Also, I see a `!` in there. You really want to avoid doing force unwrapping operations, as if it fails, it will crash. But if you remove that extraneous `?`, you won't need to force unwrap it... – Rob Nov 30 '21 at 16:35
  • I changed to ```guard let heartRate = message.values.first as? Int else { return``` and then I am seeing another error saying "Initializer for conditional binding must have Optional type, not 'Double'" in the line below. let me look up on this error... – Michael Nov 30 '21 at 16:40
  • Thanks Rob :) I managed to resolve this issue and get my delegate function running by removing the "guard let" statement since the right side of equation was non-optional in the first place. How do I thank you since you didn't post answer? – Michael Nov 30 '21 at 16:46
  • 1
    I'm happy with you posting your own answer. You'll be able to accept it in a day or so... – Rob Nov 30 '21 at 16:50

1 Answers1

0

With help from @Rob in the comments, I was able to unwrap the message properly and remove unnecessary guard let statements to run my delegate function. Below is the updated piece of code.

  1. Changed message.values.first? as Int as the rate was in an integer format.
  2. Removed guard let statements in converting the heartRate into the double format, as it was non-optional.
extension WatchKitConnection: WCSessionDelegate {

func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
        print("didReceiveMessage from watch")
        print(message)
        
//        delegate?.updateLatestHeartRate(Double(message.values.first))
        
        guard let heartRate = message.values.first as? Int else {
            return
        }
        
        let heartRateDouble = Double(heartRate)
        
        print("printing heartRate double from message\(heartRateDouble)")
        
        delegate?.updateLatestHeartRate(heartRateDouble)
        
        print("updateLatestHeartRate")
        
    }
}
Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Michael
  • 370
  • 3
  • 11