简体   繁体   English

iPhone为什么不将阵列传输到Apple Watch?

[英]Why isn't iPhone transferring an array to Apple Watch?

I have an array stored on my iPhone that I need sent to the Watch in the background whenever it is updated on the phone. 我在iPhone上存储了一个数组,无论何时在手机上对其进行更新,都需要在后台将其发送到Watch。 I've followed a tutorial on RayWenderlich.com but I just can't seem to get it to work. 我已经关注了RayWenderlich.com上的教程,但似乎无法正常工作。

Phone code: 电话代码:

import UIKit
import Foundation
import WatchConnectivity

class ViewController: UIViewController, WCSessionDelegate {

var array1 = ["Hi", "This", "Is", "A", "Test"]()
var array2 = ["1", "2", "3", "4", "5"]()

 var session: WCSession?

private func startSession() {

    if WCSession.isSupported() {

        session = WCSession.defaultSession()
        session?.delegate = self
        session?.activateSession()

    }

}
private func sendToWatch() {

    if let session = session where session.reachable {

        session.transferUserInfo(["Array1": array1])

    }

    if let session = session where session.reachable {

        session.transferUserInfo(["Array2": array2])

    }

}

sendToWatch()

}

And Watch code: 并观看代码:

import WatchKit
import Foundation
import WatchConnectivity

var array1 = [String]()

var array2 = [String]()

class InterfaceController: WKInterfaceController, WCSessionDelegate {

var session: WCSession?

@IBOutlet var table: WKInterfaceTable!

override func awakeWithContext(context: AnyObject?) {
    super.awakeWithContext(context)

    startSession()

    table!.setNumberOfRows(array1.count, withRowType: "tableRowController")

    var index = 0

    while index < array1.count {

        let row = table.rowControllerAtIndex(index) as! tableRowController

        row.rowLabel.setText(array1[index])

        row.dateLabel.setText(array2[index])

        index++

    }

}

private func startSession() {

    if WCSession.isSupported() {

        session = WCSession.defaultSession()
        session?.delegate = self
        session?.activateSession()

    }

}

func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) {

    if let received1 = userInfo["Array1"] as? [String] {
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            array1 = received1
        })
    }

    if let received2 = userInfo["Array2"] as? [String] {
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            array2 = received2
        })
    }

}

}

The Table on the watch works fine if I enter dummy data into the arrays, so I know everything is set up correctly. 如果我在数组中输入伪数据,手表上的表就可以正常工作,因此我知道一切设置正确。 I'm really only having problems with the Transfer/Receiving. 我真的只在转移/接收方面有问题。

SECOND ATTEMPT: 第二次尝试:

I'm now trying to use updateApplicationContext() as opposed to transferUserInfo() . 我现在正在尝试使用updateApplicationContext()而不是transferUserInfo() I've removed the session.reachable check and changed some code. 我删除了session.reachable检查并更改了一些代码。

Phone code: 电话代码:

 private func sendToWatch() {
do {
        let applicationDict = ["Array1": array1]
        let applicationDict2 = ["Array2": array2]
        try WCSession.defaultSession().updateApplicationContext(applicationDict)
        try WCSession.defaultSession().updateApplicationContext(applicationDict2)
    }

catch {
        print(error)
    }
}

Watch code: 观看代码:

func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {

    //I can't figure out how to retrieve the data!

    print(applicationContext) // returns nil 
    array1 = applicationContext["Array1"] as! [String] //returns nil and crashes app
    array2 = applicationContext["Array2"] as! [String] //returns nil and crashes app

}

THIRD ATTEMPT: 第三尝试:

I'm now able to sometimes get either array1 or array2 to appear on the Watch. 我现在有时可以 array1或array2出现在Watch上。 Of course, it crashes the app as both arrays are not successfully received. 当然,由于未成功接收两个阵列,因此它会使应用程序崩溃。 Can anybody help me with this? 有人可以帮我吗?

Watch Code: 观看代码:

func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {

    dispatch_async(dispatch_get_main_queue()) { () -> Void in

        if let retrievedArray1 = applicationContext["Array1"] as? [String] {

            array1 = retrievedArray1

            print(array1)

        }

        if let retrievedArray2 = applicationContext["Array2"] as? [String] {

            array2 = retrievedArray2

            print(array2)

        }

        self.table!.setNumberOfRows(array1.count, withRowType: "tableRowController")

        var index = 0

        while index < array1.count {

            let row = self.table.rowControllerAtIndex(index) as! tableRowController

            row.rowLabel.setText(array1[index]) //My crash happens either here or....

            row.dateLabel.setText(array2[index])  //here because both arrays aren't being received and unreceived array is out of index

            index++

        }

    }

}

With respect to your third try: 关于您的第三次尝试:

You don't want to use updateApplicationContext - you want to use transferUserInfo, as elsewhere suggested. 您不想使用updateApplicationContext-您想要使用transferUserInfo,如其他建议的那样。

Each updateApplicationContext call will overwrite any preceding data that have have been sent to the watch. 每个updateApplicationContext调用将覆盖已发送到手表的所有先前数据。 When you send dict2 immediately after the dict1, the first dictionary is discarded and replaced with dict2. 当您在dict1之后立即发送dict2时,第一个词典将被丢弃并替换为dict2。 You cannot get both dictionaries in this way via updateApplicationContext. 您不能通过updateApplicationContext以这种方式获得两个字典。

You would use updateApplicationContext to pass, for example, settings or options in your app where only the most recent setting is important. 例如,您将使用updateApplicationContext来传递应用程序中仅最新设置很重要的设置或选项。 For example, if you have a flag that could be changed in the iOS app, you would use updateApplicationContext every time the flag was changed in the iOS app. 例如,如果您有一个可以在iOS应用程序中更改的标志,则每次在iOS应用程序中更改该标志时,都将使用updateApplicationContext。 When the watch app eventually is loaded, it will only see the last setting of the flag in didReceiveApplicationContext. 最终加载watch应用程序时,它将仅看到didReceiveApplicationContext中标志的最后设置。

The way your third try is set up now, the first dict is sent and then immediately followed by the second dict. 现在设置您的第三次尝试的方式,将发送第一个字典,然后立即发送第二个字典。 You are seeing intermittent failures based on variable lag times in the delivery of those two dictionaries. 您看到基于这两个词典的交付中的可变滞后时间的间歇性故障。

If the didReceiveApplicationContext is invoked before the second dictionary is completely transferred, you will successfully retrieve dictionary 1 since that data hasn't been overwritten yet. 如果在完全传输第二个字典之前调用didReceiveApplicationContext,则您将成功检索字典1,因为该数据尚未被覆盖。 It will fail when it tries to access index "Array 2" because it is not there yet. 当它尝试访问索引“ Array 2”时会失败,因为它还不存在。 If the second context is transferred before the watch hits the retrieve "Array 1" call, then your app will fail there because the last data received is not keyed on "Array1", but rather "Array2". 如果第二个上下文在手表到达检索“ Array 1”调用之前被传输,则您的应用将在那里失败,因为最后收到的数据不是键入“ Array1”,而是键入“ Array2”。

Calls using updateUserInfo do not overwrite preceding calls. 使用updateUserInfo进行的调用不会覆盖之前的调用。 When the watch app is loaded, it will trigger the didReceiveUserInfo code once for each call. 加载监视应用程序后,它将为每个调用触发一次didReceiveUserInfo代码。 The order of the calls is maintained, so if you sent dict1, dict2, and then dict3 from the iOS app, the watch app will get them in that order. 通话的顺序得以保持,因此,如果您从iOS应用发送了dict1,dict2和dict3,则手表应用将按照该顺序进行发送。

session.reachable will only be true when the Watch app is in the foreground (there are a few rare exceptions). session.reachable仅在Watch应用程序位于前台时才为true(有一些罕见的例外)。

If you want to send data to the watch app in the background, you should be using updateApplicationContext , transferUserInfo or transferFile (which one you choose depends on what you are sending and its size). 如果要在后台将数据发送到watch应用程序,则应使用updateApplicationContexttransferUserInfotransferFile (选择哪种取决于您要发送的内容及其大小)。

So something like: 所以像这样:

Updated code in response to 3rd edit/question by originator 更新了代码以响应创建者的第三次编辑/问题

Phone code: 电话代码:

private func sendToWatch() {
do {
        let applicationDict = ["Array1": array1, "Array2": array2]
        try WCSession.defaultSession().updateApplicationContext(applicationDict)
    }

catch {
        print(error)
    }
}

Watch code: 观看代码:

func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {

    dispatch_async(dispatch_get_main_queue()) { () -> Void in

        if let retrievedArray1 = applicationContext["Array1"] as? [String] {

            array1 = retrievedArray1

            print(array1)

        }

        if let retrievedArray2 = applicationContext["Array2"] as? [String] {

            array2 = retrievedArray2

            print(array2)

        }

        self.table!.setNumberOfRows(array1.count, withRowType: "tableRowController")

        var index = 0

        while index < array1.count {

            let row = self.table.rowControllerAtIndex(index) as! tableRowController

            row.rowLabel.setText(array1[index])

            row.dateLabel.setText(array2[index])

            index++

        }

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM