从函数中检索结果(Swift/WatchOS 2)



我有一个问题,很可能是一个概念上的问题,但我希望有人能指出我在正确的方向。我正试图从我的WatchKit扩展中的iOS应用程序接收数据字典,使用新的WCSession * didReceiveMessage*。当我打印收到的消息时,我正确地接收了数据,但是我无法在函数之外对这些数据做任何事情(例如填充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并正确打印它之后,该变量没有在其他地方填充。因此,我不能重新加载表,甚至不能在reloadTable()函数中打印,尽管我尽了最大的努力。

首先,您没有将文件分配给您的类变量,因此它在您希望它释放之前就被释放了。dispatch_async也应该在重新加载UI时使用。

我认为这里的主要问题是你试图发送你的自定义FileData对象作为字典中的字符串,但你是通过获取对象的字符串值来做到这一点,这将不起作用。您需要为您的对象添加一些自定义序列化,以便能够将其转换为可以在消息有效负载中发送的字典。下面是一个示例,说明如何使用一个具有两个属性的测试类:

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)")
                })
...

你可以从你的手表操作系统控制器读取如下消息:

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应用程序之间发送自定义对象似乎出现了一些混乱。苹果的文档显示,我们需要在发送之前将对象覆盖到NSDate中或将自定义对象序列化到只包含基础类型(NSString, NSNumber, NSDate等)的NSDictionary中。这可能会给开发人员带来很大的开销,即使他们只有几个相互关联的简单自定义对象。

为了在我自己的项目中减轻这种痛苦,我使用swift 2.0创建了一个通用的序列化器/反序列化器类,它非常易于使用,并且设计用于iOS和watchOS之间的通信。

你想要传输的每个自定义类只需要扩展Serializable类并在类的顶部添加一个@objc标签。我在上面的例子中使用的Testing类将变成:

@objc(Testing)
internal class Testing: Serializable {
    var name: String
    var someNumber: NSNumber
}

它可以在github上找到,包含一个工作示例的游乐场。

WCSessionDelegate方法和块处理程序是在串行后台队列上调用的,所以如果你想更新UI,你必须首先调度到主队列

这里我可以建议的一件事是文件变量将无法从readtable方法访问,请尝试将文件变量传递给readtable函数

也因为你已经定义了Let文件(实际上是静态的),所以什么是需要重新加载表?因为在这种情况下文件不会被更改。

您可以尝试在声明fileTable的更高级别将文件定义为变量。

请让我知道这是否有效

最新更新