从函数中检索结果 (Swift/WatchOS 2)
Retrieving Result From Function (Swift/WatchOS 2)
我遇到的问题很可能是概念性问题,但我希望有人能为我指出正确的方向。我正在尝试使用新的 WCSession * didReceiveMessage* 从我的 WatchKit 扩展中的 iOS 应用程序接收数据字典。当我打印收到的消息时,我正在正确接收数据,但我无法在函数之外对该数据执行任何操作(例如填充 WKInterfaceTable,这是我的最终目标)。
InterfaceController.swift (WatchOS):
class InterfaceController: WKInterfaceController, WCSessionDelegate {
var session : WCSession!
var files = [String]()
@IBOutlet var fileTable: WKInterfaceTable!
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Configure interface objects here.
startSession()
reloadTable()
}
private func startSession() {
if (WCSession.isSupported()) {
session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
print("activated session")
}
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
let files = message["myFiles"] as? String
print(files!)
reloadTable()
}
func reloadTable() {
print("Test: \(files)")
fileTable.setNumberOfRows(files.count, withRowType: "FileTableRowController")
for (index, file) in files.enumerate() {
if let row = fileTable.rowControllerAtIndex(index) as? FileTableRowController {
row.fileLabel.setText("test")
}
}
}
TableViewController.swift (iOS):
...
let session = WCSession.defaultSession()
print("Session is reachable: \(session.reachable)") // this is false
let msg = ["myFiles":String(self.files)]
session.sendMessage(msg, replyHandler: { reply in
print("Got reply: \(reply)")
}, errorHandler: { error in
print("error: \(error)")
})
...
似乎在 WatchKit 收到 files
并正确打印它之后,该变量没有被填充到其他地方。因此,我无法重新加载 table,甚至无法在 reloadTable()
函数中打印,尽管我已尽最大努力。
我可以在这里建议的一件事是文件变量将无法通过读取 table 方法访问,请尝试将文件变量传递给读取table 函数
另外,既然你已经通过 Let 定义了文件(几乎是静态的)那么需要重新加载什么 table?因为在这种情况下不会更改文件。
您可以尝试在清除 fileTable 的更高级别将文件定义为变量。
如果可行请告诉我
WCSessionDelegate 方法和块处理程序在串行后台队列上调用,因此如果您想更新 UI,您必须先分派到主队列
首先,您没有将文件分配给 class 变量,因此它会在您希望之前被释放。重新加载 UI 时也应使用 dispatch_async。
我认为这里的主要问题是您试图将自定义 FileData 对象作为字典中的字符串发送,但您是通过获取对象的字符串值来执行此操作的,这是行不通的。您需要添加一些对象的自定义序列化,以便能够将其转换为可以在消息有效负载中发送的字典。这是一个示例,说明如何使用具有两个属性的测试 class 执行此操作:
internal class Testing: NSObject {
var name: String
var someNumber: NSNumber
init(name: String, someNumber: NSNumber) {
self.name = name
self.someNumber = someNumber
}
func serialize() -> [String:AnyObject] {
var transfer = [String:AnyObject]()
transfer["name"] = self.name
transfer["someNumber"] = self.someNumber
return transfer
}
class func deserialize(transfer: [String:AnyObject]) -> Testing {
let deserialized = Testing(
name: transfer["name"] as! String,
someNumber:transfer["someNumber"] as! NSNumber)
return deserialized
}
}
然后您可以使用它从您的 iOS 控制器发送如下消息:
...
let session = WCSession.defaultSession()
let testing = Testing(name: "my name", someNumber: 1)
let serializedTesting = testing.serialize()
let msg = ["myFiles":serializedTesting]
session.sendMessage(msg, replyHandler: { reply in
print("Got reply: \(reply)")
}, errorHandler: { error in
print("error: \(error)")
})
...
并且您可以从手表OS控制器读取消息如下:
func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
// Pull out the serialized object
let files = message["myFiles"] as? [String:AnyObject]
// Deserialize back to object
self.files = Testing.deserialize(serializedTesting)
// Update the UI
dispatch_async(dispatch_get_main_queue()) {
reloadTable()
}
}
更新
关于如何在 iOS 应用程序和 watchOS 应用程序之间发送自定义对象,似乎出现了一些混乱。 Apple 的文档显示我们需要在发送之前将对象覆盖到 NSDate 中或将我们的自定义对象序列化到仅包含基础类型(NSString、NSNumber、NSDate 等)的 NSDictionary 中。这可能会给开发人员带来大量开销,即使他们只有几个简单的相互关联的自定义对象也是如此。
为了减轻我自己项目中的这种痛苦,我使用 swift 2.0 创建了一个通用的 serializer/deserializer class,它使用起来非常简单,并且设计为 iOS 并观看OS.
您要传输的每个自定义 class 只需要扩展可序列化 class 并在 class 顶部添加一个 @objc 标记。我在上面用作示例的测试 class 将变为:
@objc(Testing)
internal class Testing: Serializable {
var name: String
var someNumber: NSNumber
}
它在 github here 上可用,并且包含一个带有工作示例的游乐场。
我遇到的问题很可能是概念性问题,但我希望有人能为我指出正确的方向。我正在尝试使用新的 WCSession * didReceiveMessage* 从我的 WatchKit 扩展中的 iOS 应用程序接收数据字典。当我打印收到的消息时,我正在正确接收数据,但我无法在函数之外对该数据执行任何操作(例如填充 WKInterfaceTable,这是我的最终目标)。
InterfaceController.swift (WatchOS):
class InterfaceController: WKInterfaceController, WCSessionDelegate {
var session : WCSession!
var files = [String]()
@IBOutlet var fileTable: WKInterfaceTable!
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Configure interface objects here.
startSession()
reloadTable()
}
private func startSession() {
if (WCSession.isSupported()) {
session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
print("activated session")
}
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
let files = message["myFiles"] as? String
print(files!)
reloadTable()
}
func reloadTable() {
print("Test: \(files)")
fileTable.setNumberOfRows(files.count, withRowType: "FileTableRowController")
for (index, file) in files.enumerate() {
if let row = fileTable.rowControllerAtIndex(index) as? FileTableRowController {
row.fileLabel.setText("test")
}
}
}
TableViewController.swift (iOS):
...
let session = WCSession.defaultSession()
print("Session is reachable: \(session.reachable)") // this is false
let msg = ["myFiles":String(self.files)]
session.sendMessage(msg, replyHandler: { reply in
print("Got reply: \(reply)")
}, errorHandler: { error in
print("error: \(error)")
})
...
似乎在 WatchKit 收到 files
并正确打印它之后,该变量没有被填充到其他地方。因此,我无法重新加载 table,甚至无法在 reloadTable()
函数中打印,尽管我已尽最大努力。
我可以在这里建议的一件事是文件变量将无法通过读取 table 方法访问,请尝试将文件变量传递给读取table 函数
另外,既然你已经通过 Let 定义了文件(几乎是静态的)那么需要重新加载什么 table?因为在这种情况下不会更改文件。
您可以尝试在清除 fileTable 的更高级别将文件定义为变量。
如果可行请告诉我
WCSessionDelegate 方法和块处理程序在串行后台队列上调用,因此如果您想更新 UI,您必须先分派到主队列
首先,您没有将文件分配给 class 变量,因此它会在您希望之前被释放。重新加载 UI 时也应使用 dispatch_async。
我认为这里的主要问题是您试图将自定义 FileData 对象作为字典中的字符串发送,但您是通过获取对象的字符串值来执行此操作的,这是行不通的。您需要添加一些对象的自定义序列化,以便能够将其转换为可以在消息有效负载中发送的字典。这是一个示例,说明如何使用具有两个属性的测试 class 执行此操作:
internal class Testing: NSObject {
var name: String
var someNumber: NSNumber
init(name: String, someNumber: NSNumber) {
self.name = name
self.someNumber = someNumber
}
func serialize() -> [String:AnyObject] {
var transfer = [String:AnyObject]()
transfer["name"] = self.name
transfer["someNumber"] = self.someNumber
return transfer
}
class func deserialize(transfer: [String:AnyObject]) -> Testing {
let deserialized = Testing(
name: transfer["name"] as! String,
someNumber:transfer["someNumber"] as! NSNumber)
return deserialized
}
}
然后您可以使用它从您的 iOS 控制器发送如下消息:
...
let session = WCSession.defaultSession()
let testing = Testing(name: "my name", someNumber: 1)
let serializedTesting = testing.serialize()
let msg = ["myFiles":serializedTesting]
session.sendMessage(msg, replyHandler: { reply in
print("Got reply: \(reply)")
}, errorHandler: { error in
print("error: \(error)")
})
...
并且您可以从手表OS控制器读取消息如下:
func session(session: WCSession, didReceiveMessage message: [String : AnyObject]) {
// Pull out the serialized object
let files = message["myFiles"] as? [String:AnyObject]
// Deserialize back to object
self.files = Testing.deserialize(serializedTesting)
// Update the UI
dispatch_async(dispatch_get_main_queue()) {
reloadTable()
}
}
更新
关于如何在 iOS 应用程序和 watchOS 应用程序之间发送自定义对象,似乎出现了一些混乱。 Apple 的文档显示我们需要在发送之前将对象覆盖到 NSDate 中或将我们的自定义对象序列化到仅包含基础类型(NSString、NSNumber、NSDate 等)的 NSDictionary 中。这可能会给开发人员带来大量开销,即使他们只有几个简单的相互关联的自定义对象也是如此。
为了减轻我自己项目中的这种痛苦,我使用 swift 2.0 创建了一个通用的 serializer/deserializer class,它使用起来非常简单,并且设计为 iOS 并观看OS.
您要传输的每个自定义 class 只需要扩展可序列化 class 并在 class 顶部添加一个 @objc 标记。我在上面用作示例的测试 class 将变为:
@objc(Testing)
internal class Testing: Serializable {
var name: String
var someNumber: NSNumber
}
它在 github here 上可用,并且包含一个带有工作示例的游乐场。