8

I have all the data I need in my WatchKit Extension (passed from the iOS app).

I used the data in the WatchKit InterfaceController to fill in a table, which works perfectly.

I'm trying to figure out the best way to get that same data in my WatchKit ComplicationController.

Currently, in the InterfaceController, the data gets passed in using didReceiveUserInfo:

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

    if let beachValue = userInfo["Surf"] as? String {

        places.append(Place(dataDictionary: ["Surf" : surfValue]))

    } else {
        print("Something went wrong")
    }

}

Do I need to call this same WCSession method in my ComplicationController and do the whole data grab again, or is there any easier way for me to access this same data for use in the ComplicationController?

Any help appreciated. Thanks!

EDIT:

My table function:

func makeTable() {

    // Per SO
    let myDelegate = WKExtension.sharedExtension().delegate as! ExtensionDelegate
    let accessVar = myDelegate.places
    self.rowTable.setNumberOfRows(accessVar.count, withRowType: "rows")

    for (index, evt) in accessVar.enumerate() {

        if let row = rowTable.rowControllerAtIndex(index) as? TableRowController {

            row.mLabel.setText(evt.evMat)

        } else {
            print(“No”)
        }
    }

}
SRMR
  • 3,064
  • 6
  • 31
  • 59
  • I'm wondering exactly the same :-) Apple docs at https://developer.apple.com/library/watchos/documentation/General/Conceptual/AppleWatch2TransitionGuide/CreatingaComplication.html say: // Get the complication data from the extension delegate. let myDelegate = WKExtension.sharedExtension().delegate as! ExtensionDelegate var data : Dictionary = myDelegate.myComplicationData[ComplicationCurrentEntry]! If anyone could explain an ios newbie how to apply this to my own code I would be grateful. Basically my application data is an array of custom objects. – Alex Oct 19 '15 at 07:02
  • @Alex yeah I looked at that too in the docs and was trying to figure it out. I wasn't sure if it was saying to use the `ExtensionDelegate` as the place to set up the `WCSession` info (like you might do in the `AppDelegate` for the iOS side) or what. But yeah I'm not crystal clear on it either. Let me know if you find anything! – SRMR Oct 19 '15 at 13:17

2 Answers2

12
// 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.

Antonioni
  • 578
  • 1
  • 5
  • 15
  • Hey thanks for the response, I'm going to try this and I'll let you know! – SRMR Feb 08 '16 at 21:25
  • I couldn't get the Apple's Doc link to work, so am I putting those first two lines in `ExtensionDelegate.swift` or `ComplicationController.swift`? ( `let myDelegate = WKExtension.sharedExtension().delegate as! ExtensionDelegate var data : Dictionary = myDelegate.myComplicationData[ComplicationCurrentEntry]!`) – SRMR Feb 08 '16 at 22:31
  • If you set up your ExtensionDelegate like I did then you'll have to access your variables by what you name them. I'll update this answer above to show how I'd access those variables. What errors are you getting? – Antonioni Feb 09 '16 at 22:46
  • In `ComplicationController` the error(s) "Value of type ExtensionDelegate has no member..." for both line `let accessVar = myDelegate.dataVar1` and `let myDict = myDelegate.myDictionary`. I mean, there's no `myDictionary` in `ExtensionDelegate` but there is `dataVar1` so that should be working without getting an error, but since it's not I can't figure out whats going on. Any ideas? Thanks! – SRMR Feb 11 '16 at 00:43
  • You need to declare the variables "dataVar1" and "myDictionary" in your ExtensionDelegate, like I have above, then you should not get these errors. Of course you can name these whatever names you'd like. – Antonioni Feb 11 '16 at 22:09
  • Does it make sense that I would get the errors putting that code in `someMethod` but not when I put that code in `func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void))`? – SRMR Feb 12 '16 at 01:06
  • And the data I get in my `InterfaceController` method `didReceiveUserInfo`, how do I access that data in my Complication? Do I need to put `WCSession` somewhere in my `ExtensionDelegate` or how does that work exactly? Thanks! – SRMR Feb 12 '16 at 02:13
  • Keep your array "places" inside the `ExtensionDelegate` as a variable and then you can access it from within any `Interface` controller. Thereby saving adding data to it in your `Interface` controller and accessing it from your `Complication` controller – Antonioni Feb 15 '16 at 19:10
  • I think I’m starting to begin to understand, but let me just make sure. So right now I have `var places = [Place]()` in my `InterfaceController`. So you’re saying to move the line of code `var places = [Place]()` to `ExtensionDelegate`? So that line of code will be the only thing in my `ExtensionDelegate`, right? – SRMR Feb 15 '16 at 19:25
  • Correct. So then you can always access it with: `let myDelegate = WKExtension.sharedExtension().delegate as! ExtensionDelegate` and then read from `myDelegate.places` or write to it. – Antonioni Feb 16 '16 at 19:36
  • For whatever reason, `var places = [Place]()` in `ExtensionDelegate` gets called first when I run the app, so when I'm trying to build my table, there are no items (when it runs the code `let accessVar = myDelegate.places`, why would that be? I posted my `makeTable` code above so you can see it if needed. – SRMR Feb 17 '16 at 01:04
  • `ExtensionDelegate` is similar to your `AppDelegate` and gets called first on app launch. Therefore you'll initially have an empty array. You will have to update this array either in your method `session:didReceiveUserInfo:` or some other method from `WCSession`. You could ask your iPhone app for information and get a reply back with `sendMessage:replyHandler:`. I would look into `WatchConnectivity` and see what method(s) will work best. – Antonioni Feb 18 '16 at 15:33
  • Getting stuck on a related question with implementing the `var data : Dictionary = myDelegate.myComplicationData[ComplicationCurrentEntry]!` part, if you get a chance to peek http://stackoverflow.com/questions/35542729/call-extensiondelegate-to-create-refresh-data-for-complication – SRMR Feb 22 '16 at 00:17
  • Is there some way inside of `somemethod` to update `myDict` so that it is not nil when it is accessed from `ComplicationController` etc? I found that if I hardcode a string `var dataVar2: "String"` it is accessible because it has been initialized before `WCSession` runs, but because `myDict` is nil until `WCSession` runs, I need to update it or make `ComplicationController` aware of that update you know? – SRMR Mar 31 '16 at 00:57
  • When you get your data in `session:didReceiveUserInfo:` save the data for your complication in `NSUserDefaults`. This way when the complication is loaded, you can access your up-to-date data stored in `NSUserDefaults` without relying on if your dictionary has been initialized. – Antonioni Mar 31 '16 at 13:49
  • Tried that but the complication asks for data before `session:didReceiveUserInfo:`, so I'm kinda stuck with no idea – SRMR Mar 31 '16 at 16:25
1

Well, what I have done in my app is to set up another singelton class to be responsible for fetching and holding of data for both my Watch app and complication. But that doesnt look like the best way for me. Unfortunately I do not get the Apple code

var data : Dictionary = myDelegate.myComplicationData[ComplicationCurrentEntry]!

at all. I dont understand where this myComplicationData comes from.

Alex
  • 11
  • 1
  • Yeah I'm still trying to figure it out. Hope someone swoops in an helps us out a bit, but I'll keep trying to figure it out in the mean time and let you know if I do – SRMR Oct 22 '15 at 15:43
  • You ever figure this out? – SRMR Feb 16 '16 at 02:22
  • No, I'm still using my own singleton class to hold the data for both watch app and complication... – Alex Feb 20 '16 at 04:49
  • But as Antonioni said using a singleton seems to be a valid way – Alex Jun 25 '16 at 08:10