Call ExtensionDelegate to create/refresh data for Complication
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.
WatchKit Complication: get Complication data from extension delegate
// Get the complication data from the extension delegate.
let myDelegate = WKExtension.sharedExtension().delegate as! ExtensionDelegate
var data : Dictionary = myDelegate.myComplicationData[ComplicationCurrentEntry]!
Above from Apple's Doc is just an example on storing the data you need for your complication in your extension delegate seeing as how you can access it easily as a singleton. The reference to "myComplicationData" is an example of a Dictionary and is not a parameter in the ExtensionDelegate by default.
Either set up your own class as a singleton which holds data for your watch like so:
// Access by calling:
// Model.sharedModel.modelVal1
class Model {
static let sharedModel = Model()
var modelVal1: Float!
var modelVal2: String!
}
Or use the extension delegate as your singleton and add your properties to its class like below. This will allow you to access whatever variables you create in your ExtensionDelegate.
// ExtensionDelegate.swift
class ExtensionDelegate: NSObject, WKExtensionDelegate {
var dataVar1: Float!
var dataVar2: String!
var myDictionary: [String: String]!
}
// ComplicationController.swift
import WatchKit
class ComplicationController: NSObject, CLKComplicationDataSource {
func someMethod() {
let myDelegate = WKExtension.sharedExtension().delegate as! ExtensionDelegate
// Here is an example of accessing the Float variable
let accessVar = myDelegate.dataVar1
let myDict = myDelegate.myDictionary
}
}
Using either way will help keep your data in one spot so you can always access it from any class in your watch extension.
Calling a method in Watch ExtensionDelegate
Here is how you get an instance of your watchkit delegate:
let myDelegate = WKExtension.sharedExtension().delegate as! ExtensionDelegate
You can call your methods on this object.
What is the flow for updating complication data for Apple Watch?
The flow for a complication refresh that is being done on a time interval follows this sequence:
- iOS calls your function
requestedUpdateDidBegin()
orrequestedUpdateBudgetExhausted()
(If your budget is exhausted nothing you do will cause an update until you're given more execution time.) - Inside of
requestedUpdateDidBegin()
you have to callreloadTimelineForComplication()
orextendTimelineForComplication()
to specify which of your complications you want reloaded or to have data added to. If you don't do this, nothing happens! - Depending on if you called
reload
orextend
, iOS makes calls to one or both ofgetCurrentTimelineEntryForComplication()
andgetTimelineEntriesForComplication()
- Irrespective of whether or not you updated your complication, iOS calls
getNextRequestedUpdateDateWithHandler()
to find out when you next want the above steps to repeat.
Note: the last two steps don't necessarily have to happen in that order.
The process works this way so that iOS doesn't ask you to repeatedly regenerate the same data. It gives you a chance in requestedUpdateDidBegin()
to decide if your complication needs updating. If it doesn't, your code should just return. (This reduces your complication's execution time and helps avoid iOS from cutting off your app from further updates for having used its daily budget). But if you do have new data, you need to tell iOS by calling reloadTimelineForComplication()
or extendTimelineForComplication()
From what I can tell, everything you've written there looks good other than you weren't requesting a reload or extend inside requestedUpdateDidBegin()
. It's possible for your complication to be visible on the watch face in more than one position, and for different templates to have different display behaviours, so you have to invalidate all of them. Here is what my code looks like:
func requestedUpdateDidBegin() {
//Not shown: decide if you actually need to update your complication.
//If you do, execute the following code:
let server=CLKComplicationServer.sharedInstance()
for comp in (server.activeComplications) {
server.reloadTimelineForComplication(comp)
}
}
Note that besides time intervals that there are other ways to initiate refreshes including push alerts, executing reloads when your watch app runs, or using the Watch Connectivity framework with a WCSession to have your phone app send update data to be displayed immediately via transferCurrentComplicationUserInfo()
. See Updating Your Complication Data in Apple's docs for more info.
I've had success in the simulator testing update intervals as short as ten minutes. You probably shouldn't update that frequently on the real watch due to the execution time budget, but this will allow you to test your code without waiting 12 hours.
Related Topics
How to Get System Device Language, Swift iOS
Google Signin Not Calling Delegate Method After Success
How to Present Uiview (Xib) as Alert View in Swift
How to Use Third Party Lib in Embedded Dynamic Framework for iOS with Swift
Receipt Validation in iOS Returns Incorrect Info During Sandbox Testing
Add 'For...In' Support to a Class in Swift 2
Swift Unrecognized Selector Sent to Instance - What Am I Missing
Swiftui - How to Blur the Default Background Color of a View
How to Call Objective-C Instancetype Method in Swift
What Is The Purpose of Launch Images in an iOS Application
Simulator Vs Physical Device: Navigationlink Broken After One Use
Responseserializer 'Cannot Call Value of Non-Function Type 'Nshttpurlresponse'' with Swift 3
How to Lock Viewcontroller in Portrait Mode
Multiple Async Requests at Once in Objective C
Activity Indicator in iOS Launch Screen Doesn't Animate
iOS Getting My Location Regularly and Setting Button to Get My Location - Google Map Not Working
Conforming to UItableviewdelegate and UItableviewdatasource in Swift
Swift 3: Transfer Utility Enumeratetoassignblocks Method Signature