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. I've followed a tutorial on RayWenderlich.com but I just can't seem to get it to work.
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()
. I've removed the session.reachable
check and changed some code.
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. 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++
}
}
}
session.reachable will only be true when the Watch app is in the foreground (there are a few rare exceptions).
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).
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++
}
}
}