0

I'm running into a problem where if I run my app in the Watch Simulator before the iPhone Simulator, there is no data in the Watch app.

This is because I get the Watch data from the iPhone app (where I query Parse and save the results to the Group Defaults where the Watch can access it), since from what I believe we have been told there is no way to run this sort of function in the Watch app (extension).

Am I incorrect about that?

How am I supposed to populate the Watch app the first time it runs, if the iPhone app has not run yet?

iPhone TableViewController.m:

- (void)viewDidLoad {
    PFQuery *query = [self queryForTable];
    // ... Query Parse to find data, then save it App Group...
    NSString *container = @"group.com.me.off";
    NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:container];
    // ... finish saving to App Group
}

Watch `InterfaceController.m':

- (void)awakeWithContext:(id)context {
    [super awakeWithContext:context];
    // Initialize Parse.
    [Parse setApplicationId:@"xxx"
                  clientKey:@"xxx"];

    // GMT Date from Phone
    NSDate *gmtNow = [NSDate date];
    NSLog(@"GMT Now: %@", gmtNow);

    // Query Parse
    PFQuery *query = [PFQuery queryWithClassName:@"na"];

    [query whereKey:@"dateGame" greaterThanOrEqualTo:gmtNow];

    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        if (!error) {
            NSMutableArray *localMatchup = [@[] mutableCopy];

            for (PFObject *object in objects) {
                // Add objects to local Arrays
                [localMatchup addObject:[object objectForKey:@"matchup"]];

                // App Group
                NSString *container = @"group.com.me.off";
                NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:container];

                // Matchup
                [defaults setObject:localMatchup forKey:@"KeyMatchup"];
                NSArray *savedMatchup = [defaults objectForKey:@"KeyMatchup"];
                NSLog(@"Default Matchup: %@", savedMatchup);
                savedMatchup = self.matchupArray;
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"Say you went to dispatch");
            });   
        }
    }];

    // App Group
    NSString *container = @"group.com.me.off";
    NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:container];

    // Matchup
    NSArray *savedMatchup = [defaults objectForKey:@"KeyMatchup"];
    self.matchupArray = savedMatchup;
}

- (void)willActivate {
    [super willActivate];

    // Hide "No Games" Label
    if ([self.matchupArray count] > 0) {

        self.noGamesLabel.hidden = YES;
        self.rowTable.hidden = NO;

        [self.rowTable setNumberOfRows:[self.matchupArray count] withRowType:@"rows"];

        for (NSInteger index = 0; index < [self.timeArray count]; index++) {
            // Matchup
            NSString *matchupString = [self.matchupArray objectAtIndex:index];
            RowController *controller = [self.rowTable rowControllerAtIndex:index];
            [controller.matchupLabel setText:matchupString];
        }
    }
    // Show "No Games" Label
    else {
        self.rowTable.hidden = YES;
        self.noGamesLabel.hidden = NO;
    }  
}
SRMR
  • 3,064
  • 6
  • 31
  • 59

1 Answers1

1

You can query Parse from you extension and you can write to the group defaults. Your extension can make URL requests just like your iOS app. You will want to be careful to not block the main thread while the query is running. You will need to have some initial UI to show the user you are querying for initial data so that the app doesn't look frozen.

Stephen Johnson
  • 5,293
  • 1
  • 23
  • 37
  • Would I be doing the query in `awakeWithContext:` then? I didn't realize we could actually do that sort of work in an extension. And how would you advise to not block the main thread while that query is running? Thanks! – SRMR Mar 11 '15 at 23:06
  • You can kick off the query in `awakeWithContext`. You will want to use one of the query in background methods that Parse has (i.e. `findObjectsInBackground`). – Stephen Johnson Mar 11 '15 at 23:14
  • Ok perfect, I know how to do both of those then, will do. Last Q, do you have an idea of how we are supposed to have some initial UI to show? I'm not aware of how to go about doing that in the extension. – SRMR Mar 11 '15 at 23:16
  • You can have a simple initial UI in you app that you can turn on/off via the hidden property on the elements. Apple said to be careful to not have too many hidden elements as it can affect scrolling performance. If you have a simple message and maybe an image animation for a spinner you could unhide that on the initial run. – Stephen Johnson Mar 11 '15 at 23:43
  • Perfect. I set up a separate question I was hoping you could peek at related to your answer: http://stackoverflow.com/questions/29051061/parse-query-in-watchkit – SRMR Mar 14 '15 at 17:09
  • I'm getting a crash saying: *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'You have to call setApplicationId:clientKey: on Parse to configure Parse.', in the WatchKit extension – SRMR Mar 14 '15 at 17:40
  • Which I have in my App Delegate, but it seems to not communicate w the extension at all, so i added `[Parse setApplicationId:@"xxx" clientKey:@"xxx"];` into the beginning of my `awakeWithContext:`... that seems to be grabbing the data, but how do I refresh the view like you were saying? – SRMR Mar 14 '15 at 18:10
  • Any chance you could let me know what you think on this? Thanks! – SRMR Mar 16 '15 at 13:43
  • Do you know how I'd update the interface once I get the data? Right now I have the initial UI, but once the data is obtained from the query I am not sure how to update the UI. Thanks! – SRMR Mar 18 '15 at 01:00
  • Set IBOutlets on your WKInterfaceController class that you wire up to elements in your storyboard. Then update the text, images, tables, on those objects. Each WatchKit interface element has a setXYZ to set the correct content for it. – Stephen Johnson Mar 18 '15 at 03:22
  • What sort of method do you suggest to run to do the updating in WatchKit? Thanks! – SRMR Mar 18 '15 at 16:04
  • I guess I'm not fully understanding where/how to do the setXYZ part from what I have in my code I posted – SRMR Mar 19 '15 at 13:48
  • You have one example in your code with `[controller.mLabel setText:mString]` – Stephen Johnson Mar 19 '15 at 13:51
  • Yeah so I already have it in that `willActivate` part, so where else would I put it so that it runs again once the `Parse` query has run to update the UI? I can't figure out what the best spot for that would be in WatchKit ya know? – SRMR Mar 19 '15 at 14:20
  • I edited my question to show the code I have now in both my `awakeWithContext` and `willActivate` so you could see what I have going on, since I'm not sure where I would `setXYZ` again other than the spot I already have it in my `willActivate`. Let me know what you think, thanks!! – SRMR Mar 19 '15 at 14:46
  • Maybe I run it inside of my background `Parse` query? If so, I'm not sure how to call the update there still, would I call `[self willActivate]` or something so it runs the code to update the rows again or something? Because I can't use the same exact code as in my `willActivate` because its referencing `index` ya know? – SRMR Mar 19 '15 at 15:22