Call ExtensionDelegate to create/refresh data for

2019-01-20 14:31发布

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

}

2条回答
神经病院院长
2楼-- · 2019-01-20 14:54

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 a WatchConnectivity method like sendMessage:replyHandler:errorHandler: to receive new information.

You can use NSUserDefaults to store your imperative data that will be used in your ComplicationController, then load this information from NSUserDefaults 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.

查看更多
劫难
3楼-- · 2019-01-20 15:02

TL/DR: Have the extension tell ClockKit to update the complication after the data is received.

First issue:

So my array extEvnts is empty in my ComplicationController.swift ... Because my ExtensionDelegate.swift hasn't gotten called yet, which is what creates the data for the array

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.

Remember that background transfers are not be delivered immediately. The system sends data as quickly as possible but transfers are not instantaneous, and the system may delay transfers slightly to improve power usage. Also, sending a large data file requires a commensurate amount of time to transmit the data to the other device and process it on the receiving side.

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

Complications exist entirely in the WatchKit extension. Their user interface is not defined in the Watch app. Instead, it is defined by an object implementing the CLKComplicationDataSource protocol. When watchOS needs to update your complication, it launches your WatchKit extension. However, the Watch app’s executable is not launched.

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.

Complications aren't meant to be frequently updated. Complications should provide as much data as possible during each update cycle. You shouldn't ask the system to update your complication within minutes. You should provide data to last for many hours or for an entire 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 the CLKComplicationServer 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 and transferUserInfo.

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.

查看更多
登录 后发表回答