“邮件回复花了太长时间。” - 观察Watch OS 3的连接问题 [英] "Message reply took too long." - Watch Connectivity Issues with Watch OS 3

查看:203
本文介绍了“邮件回复花了太长时间。” - 观察Watch OS 3的连接问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的项目中,我使用 Watch Connectivity 向Watch和iPhone发送消息。我可以向手机发送消息并在启动应用程序时收到一串字符串,但是在使用操作时我收到以下错误;

In my project, I use Watch Connectivity to send messages to and from the Watch and iPhone. I can send a message to the phone and receive an array of strings when launching the app, however when using actions I get the following error;


错误域名= WCErrorDomain代码= 7012邮件回复花了太长时间。

Error Domain=WCErrorDomain Code=7012 "Message reply took too long."

以下是设置方式;

首先,手表向手机发送信息,然后手机发送一个数组字符串显示在 WKInterfaceTable 中。这有时适用于加载应用程序。 (我获取所有名为 Items 的NSManagedObjects并使用他们的 title 字符串属性存储在数组中名为 watchItems

First, the watch sends a message to the phone and then the phone sends an array of strings to display in a WKInterfaceTable. This sometimes works when loading the app. ( I fetch all NSManagedObjects called Items and use their title string properties to store in an array called watchItems.

但是,我在手表上有一个动作要删除全部数组中的项目并使用新数据刷新表。

However, I have an action on the watch to delete all items in the array and refresh the table with the new data.

手表上的操作使用 sendMessage 函数将项目发送到手机以从阵列中删除,然后手机将新更新的阵列发送到手表,手表更新表格。但是,我要么得到相同的数组返回或错误。

The action on the watch uses a sendMessage function to send the item to the phone to delete from the array, then the phone sends the newly updated array to the watch and the watch updates the table. However, I either get the same array back or an error.

非常简单,所以在Swift 3和Watch OS3 / iOS 10之前一切正常工作;整个应用程序曾经工作过。

Pretty simple right, so everything actually worked fine before Swift 3 and Watch OS3/iOS 10; the entire app used to work.

以下是我设置所有内容的方法;

Here's how I have everything set up;

电话应用代表

import WatchConnectivity

class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {

var session : WCSession!

var items = [Items]()

func loadData() {
    let moc = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
    let request = NSFetchRequest<Items>(entityName: "Items")

    request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: true)]
    request.predicate = NSPredicate(format: "remove == 0", "remove")

    do {
        try
            self.items = moc!.fetch(request)
        // success ...
    } catch {
        // failure
        print("Fetch failed")
    }
}

//WATCH EXTENSION FUNCTIONS
//IOS 9.3 
/** Called when the session has completed activation. If session state is WCSessionActivationStateNotActivated there will be an error with more details. */


//HAVE TO INCLUDE
@available(iOS 9.3, *)
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?){
   print("iPhone WCSession activation did complete")
}


@available(iOS 9.3, *)
func sessionDidDeactivate(_ session: WCSession) {}

func sessionWatchStateDidChange(_ session: WCSession) {}

func sessionDidBecomeInactive(_ session: WCSession) {

}

//APP DELEGATE FUNCTIONS

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {

    //Check if session is supported and Activate
    if (WCSession.isSupported()) {
        session = WCSession.default()
        session.delegate = self;
        session.activate()
    }
    return true
}


}

//DID RECIEVE MESSAGE
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Swift.Void) {


    loadData()

    func loadItems() {
        watchItems.removeAll()

        for a in self.items {
            watchItems.append(a.title)
        }
    }

    var watchItems = ["1","2","3","4","5"]

    let value = message["Value"] as? String

    //This is called when user loads app, and takes some time when using refresh action, sometimes times out 

    if value == "HELLOiPhone/+@=" {

        print("Hello Message Recieved")

        loadItems() 

        //send a reply
        replyHandler( [ "Items" : Items ] )

    }

    //Not sure if receiving but does not delete array and send back to watch
    if value == "removeALL@+=-/" {                        
        for index in self.items {
            index.remove = 1
            //Saves MOC
        }

        loadData()
        loadTasksData()

        //send a reply
        replyHandler( [ "Items" : Items ] )

    }
    else {
        for index in self.items {
            if index.title == value {
            index.remove = 1
            //Saves MOC
            }
        }

        loadData()
        loadTasksData()

        //send a reply
        replyHandler( [ "Items" : Items ] )
    }
}

观看

import WatchConnectivity

class SimplelistInterfaceController: WKInterfaceController, WCSessionDelegate  {


/** Called when the session has completed activation. If session state is WCSessionActivationStateNotActivated there will be an error with more details. */
@available(watchOS 2.2, *)
public func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {

   //Fetch data is a function which sends a "HELLOiPhone/+@=" message to receive the array and displays in the table. This works 
   fetchData()
}


var session : WCSession!
var items = ["Refresh Items"]

override func didAppear() {
    fetchData()
}

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

override func awake(withContext context: Any?) {
    super.awake(withContext: context)
    fetchData()
}

@IBAction func refresh() {
    print("Refresh")
    //Works but sometimes message is delayed
    fetchData()
}

@IBAction func removeAll() {
    print("Remove All Items is called")
    if WCSession.default().isReachable {
        let messageToSend = ["Value":"removeALL@+=-/"]
        print("\(messageToSend)")
        session.sendMessage(messageToSend, replyHandler: { replyMessage in
            if let value = replyMessage["Items"] {
                self.items = value as! [String]

                Not receiving message
                print("Did Recieve Message, items = \(self.items)")
            }

            }, errorHandler: {error in
                // catch any errors here
                print(error)
        })
    }
    fetchData()
}

}


推荐答案


  1. 您不应该从一个目标(iOS)向第二个目标(watchOS)发送或接收自定义类对象,而应该以字典格式发送/接收数据,例如[String:Any],此字典应包含您的自定义对象需要简单字典中键值对中的属性。这可以很容易地在手表端解码。

  1. You should not send or receive custom class objects from one target(iOS) to second target(watchOS) instead you should send/receive data in dictionary format such as [String: Any] and this dictionary should contain array of your custom objects required properties in key value pair in simple dictionary. This could easily be decodable at watch side.

你应该创建一个解耦类来扩展WCSessionDelegate,如下所示,这样这个类不仅可以在ExtensionDelegate中使用,而且也可以在任何WKInterfaceController中。

You should make a decoupled class extending WCSessionDelegate such as below so that this class could be used not only in ExtensionDelegate but also in any WKInterfaceController.

class WatchSessionManager: NSObject, WCSessionDelegate {

    static let sharedManager = WatchSessionManager()

    private override init() {
        super.init()
        self.startSession()
    }

    private let session: WCSession = WCSession.default

    func startSession() {
        session.delegate = self
        session.activate()
    }

    func tryWatchSendMessage(message: [String: Any], completion: (([String: Any]) -> Void)? = nil) {
        print("tryWatch \(message)")
        weak var weakSelf = self
        if #available(iOS 9.3, *) {
            if weakSelf?.session.activationState == .activated {
                if weakSelf?.session.isReachable == true {
                    weakSelf?.session.sendMessage(message,
                                                  replyHandler: { [weak self]  ( response )  in
                                                    guard let slf = self else {return}
                                                    //Get the objects from response dictionary
                                                    completion?(response)
                        },
                                                  errorHandler: { [weak self] ( error )  in
                                                    guard let slf = self else {return}
                                                    print ( "Error sending message: % @ " ,  error )
                                                    // If the message failed to send, queue it up for future transfer
                                                    slf.session.transferUserInfo(message)
                    })
                } else {
                    self.session.transferUserInfo(message)
                }
            }else{
                self.session.activate()
                self.session.transferUserInfo(message)
            }
        } else {
            // Fallback on earlier versions
            if self.session.activationState == .activated {
                if self.session.isReachable == true {
                    self.session.sendMessage(message,
                                             replyHandler: {  ( response )  in
                                                //Get the objects from response dictionary
                                                completion?(response)
                    },
                                             errorHandler: {  ( error )  in
                                                print ( "Error sending message: % @ " ,  error )
                                                // If the message failed to send, queue it up for future transfer
                                                self.session.transferUserInfo(message)
                    })
                } else {
                    self.session.transferUserInfo(message)
                }
            }else{
                self.session.activate()
                self.session.transferUserInfo(message)
            }
        }
    }


}


现在您可以轻松地向您的iOS应用发送消息,以唤醒并从中获取数据(例如从CoreData获取)使用上述内容任何WKInterfaceController中的函数和完成块都会有你需要的数据,比如

Now you could easily send a message to your iOS app to wake up and get data from there (e.g from CoreData) using the above function in any WKInterfaceController and the completion block will have your required data such as

let dict: [String: Any] = ["request": "FirstLoad"]
WatchSessionManager.sharedManager.tryWatchSendMessage(message: dict,completion:{ (data) in print(data)})

同样的方式您应该在iOS端使用此WatchSessionManager并接收请求,并根据请求的密钥,您应从核心存储/ db中获取数据,并在didreceiveMessage函数的replyHandler中以简单的键值字典模式发送自定义对象列表,如下所示。 / p>

Same way you should use this WatchSessionManager on iOS side and receive the request and as per the requested key you should take data from core storage/db and send list of custom objects in simple key-value Dictionary pattern within replyHandler of didreceiveMessage function such as below.

 func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {
 var dict: [String: Any] = [String: Any]()
 replyHandler(dict) //This dict will contain your resultant array to be sent to watchApp.
}

有些时候,iOS App App(Killed状态)无法访问WatchApp,无法解决那个问题你应该在Timer中以大约3秒的间隔调用tryWatchSendMessage。当您从watchApp获得连接时,您应该使计时器无效。

Some time iOS App(Killed state) is not reachable to WatchApp, for solving that problem you should call "tryWatchSendMessage" within Timer of around 3 sec interval. And when you get connection from watchApp then you should invalidate the timer.

WatchConnectivity的sendMessage功能非常强大,可以唤醒您的应用程序。您应该以优化的方式使用它。

The sendMessage functionality of WatchConnectivity is so powerful to wake your app up. You should use it in optimized manner.

这篇关于“邮件回复花了太长时间。” - 观察Watch OS 3的连接问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆