使用WatchConnectivity获取核心数据获取请求
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用WatchConnectivity获取核心数据获取请求相关的知识,希望对你有一定的参考价值。
我目前正在尝试从我的ios应用程序获取CoreData数据到watchOS扩展。我正在使用WatchConnectivity Framework通过sendMessage(_ message: [String : Any], replyHandler: (([String : Any]) -> Void)?, errorHandler: ((Error) -> Void)? = nil)
函数获取字典。基本连接正常。 iOS应用程序是可以访问的,如果我尝试回复示例字典,一切正常。
到目前为止一切都很好,但是当我开始在后台的iOS应用程序上执行获取请求时,Watch App从不接收数据。过了一会儿我才得到这个错误:Error while requesting data from iPhone: Error Domain=WCErrorDomain Code=7012 "Message reply took too long." UserInfo={NSLocalizedFailureReason=Reply timeout occurred., NSLocalizedDescription=Message reply took too long.}
如果我在iPhone上打开iOS应用程序并重新启动Watch App,则回复处理程序将获得结果。但是迫使用户在iPhone上主动打开iOS应用程序是没用的。
有人可以解释为什么会这样吗?什么是正确的方法呢?自WatchOS 2以来,应用程序组似乎已经过时了。 我正在使用Swift 4 btw ......
在Apple Watch上:
import WatchConnectivity
class HomeInterfaceController: WKInterfaceController, WCSessionDelegate {
// (…)
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
session.sendMessage(["request": "persons"],
replyHandler: { (response) in
print("response: (response)")
},
errorHandler: { (error) in
print("Error while requesting data from iPhone: (error)")
})
}
在iPhone上:
import CoreData
import WatchConnectivity
class ConnectivityHandler: NSObject, WCSessionDelegate {
var personsArray:[Person] = []
// (…)
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
// only using the next line is working!
// replyHandler(["data": "test"])
if message["request"] as? String == "persons" {
fetchAllPersons()
var allPersons: [String] = []
for person in personsArray {
allPersons.append(person.name!)
}
replyHandler(["names": allPersons])
}
}
// this seems to be never executed (doesn't matter if it's in an extra function or right in the didReceiveMessage func)
func fetchAllPersons() {
do {
// Create fetch request.
let fetchRequest: NSFetchRequest<Person> = Person.fetchRequest()
// Edit the sort key as appropriate.
let sortDescriptor = NSSortDescriptor(key: #keyPath(Person.name), ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
personsArray = try DatabaseController.getContext().fetch(fetchRequest)
} catch {
fatalError("Failed to fetch: (error)")
}
}
在研究这个问题后,我自己找到了解决方案。问题是我正在使用sendMessage(_:replyHandler:errorHandler:)
协议。这仅用于在两个应用程序都处于活动状态时传输数据。
使用
sendMessage(_:replyHandler:errorHandler:)
或sendMessageData(_:replyHandler:errorHandler:)
方法将数据传输到可访问的对应方。这些方法旨在用于iOS应用和WatchKit扩展之间的即时通信。 isReachable属性当前必须为true才能使这些方法成功。
如果要在后台传输数据,则必须根据需要使用updateApplicationContext(_:)
或transferUserInfo(_:)
。这正是我所需要的!
使用
updateApplicationContext(_:)
方法将最近的状态信息传递给对方。当对方醒来时,它可以使用此信息来更新自己的状态。例如,支持后台应用程序刷新的iOS应用程序可以使用其部分后台执行时间来更新相应的Watch应用程序。此方法会覆盖以前的数据字典,因此当您的应用仅需要最新的数据值时,请使用此方法。使用
transferUserInfo(_:)
方法在后台传输数据字典。您发送的词典排队等待传递给对方,并在当前应用程序暂停或终止时继续传输。
现在,如果iPhone App对应打开ApplicationContext或UserInfo队列通过,我可以将数据添加到我的核心数据库。
遗憾的是,大多数WatchConnectivity
方法都有时间限制(正如错误告诉你的那样)并且看起来你的CoreData请求花费了太多时间,因此超出了时间限制。根据this Q&A,您似乎需要采取特定的预防措施,在后台进行CoreData查询,这可能是您的问题的原因。
但是,为了获得最佳用户体验,我建议您停止使用CoreData
和WatchConnectivity
框架,因为后者要求您的iOS应用程序至少在后台运行,因此使watchOS应用程序依赖于iOS应用程序的状态并降级watchOS上的用户体验。我建议您切换到Realm,因为Realm
完全支持watchOS,因此您的watchOS应用程序可以完全独立于您的iOS应用程序,使用户体验更加流畅,因为用户不必启动iOS应用程序并等待使用WatchConnectivity
框架通过BLE进行数据传输。
以上是关于使用WatchConnectivity获取核心数据获取请求的主要内容,如果未能解决你的问题,请参考以下文章
如果此 iPhone 与 Apple Watch 连接或未通过 WatchConnectivity 连接,我可以获取信息吗?
如何使用 WatchConnectivity 在我的 iOS 和 Watch 应用程序之间共享信息?
使用 WatchConnectivity 框架的独立手表应用