Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
146 views
in Technique[技术] by (71.8m points)

ios - Parse Query in WatchKit

I do a Parse query in my iPhone app, but I am getting errors trying to do the same Parse query in my Watch app.

This is the query in my iPhone app:

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

    // Query Parse
    PFQuery *query = [self queryForTable];
    [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 = matchupArray;
            }

            dispatch_async(dispatch_get_main_queue(), ^{
                [self.tableView reloadData];
            });

        }
    }];
}

This is the query I tried in my WatchKit app...

- (void)awakeWithContext:(id)context {
    // GMT Date from Phone
    NSDate *gmtNow = [NSDate date];
    NSLog(@"GMT Now: %@", gmtNow);

    // Query Parse
    PFQuery *query = [self queryForTable];
    [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(), ^{
                [self.tableView reloadData];
            });
        }
    }];
}

But I get errors on these two lines...

`PFQuery *query = [self queryForTable];`

`[self.tableView reloadData];`

because I can't do the same exact code related to a table I'm guessing, but I'm just not sure what to change it to.

EDIT: Adding code per @cnoon answer

WatchKit InterfaceController.m:

How would I ask for my query to run here? - (void)awakeWithContext:(id)context { [super awakeWithContext:context];

    [WKInterfaceController openParentApplication:nil reply:^(NSDictionary *replyInfo, NSError *error) {
        // What to put here?
        NSLog(@"Open Parent Application");
    }];

-and-

iPhone AppDelegate.h

How would I ask for my PFQuery to run?

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void(^)(NSDictionary *replyInfo))reply {
    // What to put here?
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There's no such thing as a UITableView in a WatchKit application. Instead, you have to work with WKInterfaceTable. Before you continue, I'd also suggest you read through the documentation in the WatchKit Programming Guide. It will give you a MUCH better understanding of all the toolsets available to you as an aspiring Apple Watch developer.

WKInterfaceTable

Once you know the ins and outs of a WKInterfaceTable, you'll quickly see why your approach is flawed for two reasons. First off, you don't have a reloadData method. The alternative in WatchKit is to setNumberOfRows(_:withRowTypes:). Then you need to iterate through each row and configure it.

PFQuery in WatchKit Extension

The second reason you are going to have issues is due to your use of PFQuery.

This is a bit of side advice, so take it or leave it. I'm speaking from experience here having already built a very large page-based Watch App that heavily communicates with the iOS App.

I would advise you to stop making PFQuerys in your WatchKit Extension. The reason is that users using your Watch App are only going to have the app open for a second or two. Everything will happen extremely fast. Because of this, it is extremely difficult to guarantee the success of network calls before the Watch App is terminated by the user. This makes things MUCH more difficult, but is simply the way it is.

Instead, you want to run your PFQuery calls on the iOS App and return that information back to the Watch Extension through the following calls:

You can also cache the PFQuery into the shared app group using MMWormhole or a similar approach alternative. Below is an example of how you can have your Watch Extension request the iOS Application to run a PFQuery, cache the data in MMWormhole and notify the Watch Extension once it is finished. By always reading the data out of the cache, you have a consistent mechanism whether the Watch Extension was still running as well as closed and re-opened.


Objective-C

InterfaceController.m

- (void)willActivate {
    [super willActivate];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        [WKInterfaceController
         openParentApplication:@{@"pfquery_request": @"dumm_val"}
         reply:^(NSDictionary *replyInfo, NSError *error) {
             NSLog(@"User Info: %@", replyInfo);
             NSLog(@"Error: %@", error);

             if ([replyInfo[@"success"] boolValue]) {
                 NSLog(@"Read data from Wormhole and update interface!");
             }
        }];
    });
}

AppDelegate.m

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply {
    if (userInfo[@"pfquery_request"]) {
        NSLog(@"Starting PFQuery"); // won't print out to console since you're running the watch extension

        // 1. Run the PFQuery
        // 2. Write the data into MMWormhole (done in PFQuery completion block)
        // 3. Send the reply back to the extension as success (done in PFQuery completion block)

        reply(@{@"success": @(YES)});
    }

    reply(@{@"success": @(NO)});
}

Swift

InterfaceController.swift

override func willActivate() {
    super.willActivate()

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Float(NSEC_PER_SEC))), dispatch_get_main_queue()) {
        WKInterfaceController.openParentApplication(["pfquery_request": "dummy_val"]) { userInfo, error in
            println("User Info: (userInfo)")
            println("Error: (error)")

            if let success = (userInfo as? [String: AnyObject])?["success"] as? NSNumber {
                if success.boolValue == true {
                    println("Read data from Wormhole and update interface!")
                }
            }
        }

        return
    }
}

AppDelegate.swift

func application(
    application: UIApplication!,
    handleWatchKitExtensionRequest userInfo: [NSObject : AnyObject]!,
    reply: (([NSObject : AnyObject]!) -> Void)!)
{
    if let pfqueryRequest: AnyObject = (userInfo as? [String: AnyObject])?["pfquery_request"] {
        println("Starting PFQuery") // won't print out to console since you're running the watch extension

        // 1. Run the PFQuery
        // 2. Write the data into MMWormhole (done in PFQuery completion block)
        // 3. Send the reply back to the extension as success (done in PFQuery completion block)

        reply(["success": true])
    }

    reply(["success": false])
}

Hopefully that helps break down the complexity of having a consistent way to read data from the cache as well as offload network requests (or PFQueries) to the iOS App.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...