All my data creation is done in the ExtensionDelegate.swift
.
The problem is ExtensionDelegate.swift
doesn't get called before the function getCurrentTimelineEntryForComplication
in my ComplicationController.swift
.
Any ideas? Here is my code and details:
So my array extEvnts
is empty in my ComplicationController.swift
:
func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) {
let extEvnts = ExtensionDelegate.evnts
}
Because my ExtensionDelegate.swift
hasn't gotten called yet, which is what creates the data for the array:
class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate {
private let session = WCSession.defaultSession()
var receivedData = Array<Dictionary<String, String>>()
static var evnts = [Evnt]()
func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) {
if let tColorValue = userInfo["TeamColor"] as? String, let matchValue = userInfo["Matchup"] as? String {
receivedData.append(["TeamColor" : tColorValue , "Matchup" : matchValue])
ExtensionDelegate.evnts.append(Evnt(dataDictionary: ["TeamColor" : tColorValue , "Matchup" : matchValue]))
} else {
print("tColorValue and matchValue are not same as dictionary value")
}
}
func applicationDidFinishLaunching() {
// Perform any final initialization of your application.
if WCSession.isSupported() {
session.delegate = self
session.activateSession()
}
}
}
EDIT:
Per Apple, it looks like this has something to do with it, but for some reason I have no idea how to actually implement it because I'm not able to call mydelegate.evnts
:
// Get the complication data from the extension delegate.
let myDelegate = WKExtension.sharedExtension().delegate as! ExtensionDelegate
var data : Dictionary = myDelegate.myComplicationData[ComplicationCurrentEntry]!
So I've tried something like this, and still can't get it working because I'm still getting no data:
func someMethod() {
let myDelegate = WKExtension.sharedExtension().delegate as! ExtensionDelegate
let dict = ExtensionDelegate.evnts
print("ExtensionDel.evnts: \(dict.count)")
}
Useful question that helped me here
In the function
requestedUpdateDidBegin()
you can update the information that you will display in your complication. So in this method you may make a call to your parent app using aWatchConnectivity
method like sendMessage:replyHandler:errorHandler: to receive new information.You can use
NSUserDefaults
to store your imperative data that will be used in yourComplicationController
, then load this information fromNSUserDefaults
for your complication. I store this data in user defaults so that I always have old data to display in case the new data fails to load.TL/DR: Have the extension tell
ClockKit
to update the complication after the data is received.First issue:
Your array is empty because the data hasn't been received at that point.
You can't (get the complication controller to) force the watch (extension) to receive data which may not have even been transmitted yet.
If you look at the WCSession Class Reference,
transferUserInfo
queues data to be transferred in the background, when the system decides it's a good time to send the info.Second issue:
You're trying to combine updating your app and your complication based on data sent from your phone. But your app and your complication don't necessarily run together. It's not surprising or unexpected that the watch updates the complication before any data has even been sent/received. The App Programming Guide for watchOS mentions that
There's no mechanism for the complication controller to say, "Wait, I'm not ready to provide an update. The complication controller can't wait on (or as mentioned, force) the watch extension to receive data.
It's only responsibility is to immediately return data based on what's currently available to it. If there's no data, it must return an empty timeline.
Approaching this problem:
You shouldn't necessarily think of app updates and complication updates as the same thing. The first is not budgeted, but the second is budgeted. If you update your complication too often, you may exceed your daily budget, and no further updates will occur for the remainder of the day.
Having covered that, you could wait until your extension has received data, then can ask
ClockKit
to extend your timeline, so new entries can be added to it.extendTimelineForComplication:
is documented in theCLKComplicationServer
Class reference.As an aside, if your data is urgent, you should use
transferCurrentComplicationUserInfo
. It's a high-priority message, which is placed at the head of the queue, and the extension is woken up to receive it. See this answer for a comparison between it andtransferUserInfo
.You also could setup a singleton to hold your data which the watch app and complication controller both use. This was mentioned in an answer to an old question of yours, and also recommended by an Apple employee on the developer forums.