目前,我正在尝试将CoreData数据从我的iOS应用程序获取到watchOS扩展。我使用WatchConnectivity框架通过sendMessage(_ message: [String : Any], replyHandler: (([String : Any]) -> Void)?, errorHandler: ((Error) -> Void)? = nil)函数获得字典。基本的连接工作正常。iOS应用程序是可访问的,如果我试图回复一个示例字典,一切都正常。
到目前为止还不错,但是当我开始在后台的iOS应用程序上执行一个获取请求时,Watch应用程序从未接收过数据。过了一会儿,我得到了一个错误: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.}
如果我在iOS上打开iPhone应用程序并重新启动Watch应用程序,应答处理程序就会得到结果。但是强迫用户在iPhone上主动打开iPhone应用程序是没用的。
有人能解释一下为什么会发生这种事吗?正确的方法是什么?从watchOS 2开始,App组似乎就过时了。
我用的是Swift 4的…
苹果手表上:
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)")
}
}发布于 2018-03-02 16:49:50
在调查了这个问题之后,我自己找到了解决办法。问题是我使用的是sendMessage(_:replyHandler:errorHandler:)协议。这只用于在两个应用程序都处于活动状态时传输数据。
使用
sendMessage(_:replyHandler:errorHandler:)或sendMessageData(_:replyHandler:errorHandler:)方法将数据传输到可访问的对应方。这些方法用于您的iOS应用程序和WatchKit扩展之间的即时通信。isReachable属性当前必须为真,才能使这些方法成功。
如果要在后台传输数据,则必须根据需要使用updateApplicationContext(_:)或transferUserInfo(_:)。这正是我所需要的!
使用
updateApplicationContext(_:)方法将最近的状态信息传递给对应方。当对应方醒来时,它可以使用这些信息来更新自己的状态。例如,支持后台app的iOS应用程序可以使用其部分后台执行时间来更新相应的Watch应用程序。此方法覆盖以前的数据字典,因此,当应用程序只需要最新的数据值时,请使用此方法。 使用transferUserInfo(_:)方法在后台传输数据字典。您发送的字典将排队等待发送给对应方,并且在当前应用程序被挂起或终止时继续传输。
现在,如果iPhone应用程序对口打开,则ApplicationContext或UserInfo队列被传递到槽中,我可以将数据添加到核心数据库中。
发布于 2017-12-10 12:29:27
遗憾的是,大多数WatchConnectivity方法都有时间限制(正如错误告诉您的那样),而且您的CoreData请求似乎花费了太多的时间,因此超过了时间限制。根据这个问答,在后台执行CoreData查询似乎需要采取特定的预防措施,因此这可能是引发问题的原因。
然而,为了获得最佳的用户体验,我建议您停止使用CoreData和WatchConnectivity框架,因为后者要求您的iOS应用程序至少在后台运行,从而使watchOS应用程序依赖于iOS应用程序的状态,并降低watchOS上的用户体验。我建议您切换到领域,因为Realm完全支持watchOS,因此您的watchOS应用程序可以完全独立于您的iOS应用程序,从而使用户体验更加流畅,因为用户不必启动iOS应用程序并等待使用WatchConnectivity框架通过BLE进行数据传输。
https://stackoverflow.com/questions/47734060
复制相似问题