在我的项目中,我使用 Watch Connectivity 在 Watch 和 iPhone 之间发送消息。我可以在启动应用程序时向手机发送消息并接收字符串数组,但是在使用操作时出现以下错误;
Error Domain=WCErrorDomain Code=7012 "Message reply took too long."
这是设置的方式;
首先, watch 向手机发送一条消息,然后手机发送一个字符串数组以显示在 WKInterfaceTable 中。这有时在加载应用程序时有效。 (我获取所有名为 Items 的 NSManagedObjects 并使用它们的 title 字符串属性存储在名为 watchItems 的 array 中。
但是,我在 watch 上有一个操作,删除数组中的所有项目并用新数据刷新表。
watch 上的 Action 使用sendMessage 函数将item 发送到手机以从数组中删除,然后手机将新更新的数组发送到 watch watch 会更新表格。但是,我要么返回相同的数组,要么返回错误。
非常简单,所以在 Swift 3 和 Watch OS3/iOS 10 之前一切都正常;整个应用程序曾经工作。
这是我设置所有内容的方式;
手机应用程序代理
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()
}
}
最佳答案
您不应从一个目标 (iOS) 向第二个目标 (watchOS) 发送或接收自定义类对象,而应发送/接收字典格式的数据,例如 [String: Any] 并且此字典应包含数组您的自定义对象需要简单字典中键值对中的属性。这可以在 watch 端轻松解码。
您应该创建一个扩展 WCSessionDelegate 的解耦类,如下所示,这样该类不仅可以在 ExtensionDelegate 中使用,而且可以在任何 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 中使用上述函数,完成 block 将包含您所需的数据,例如
let dict: [String: Any] = ["request": "FirstLoad"]
WatchSessionManager.sharedManager.tryWatchSendMessage(message: dict,completion:{ (data) in print(data)})
您应该在 iOS 端使用此 WatchSessionManager 并接收请求,根据请求的键,您应该从核心存储/数据库中获取数据,并在 didreceiveMessage 函数的 replyHandler 中以简单的键值字典模式发送自定义对象列表如下所示。
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 应用程序(已终止状态)无法访问 WatchApp,为解决该问题,您应该在约 3 秒间隔的计时器内调用“tryWatchSendMessage”。当您从 watchApp 获得连接时,您应该使计时器无效。
WatchConnectivity 的 sendMessage 功能非常强大,可以唤醒您的应用程序。您应该以优化的方式使用它。
关于ios - "Message reply took too long."- Watch OS 3 的 watch 连接问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39515619/
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
由于fast-stemmer的问题,我很难安装我想要的任何rubygem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test