Pass Data from iOS query to Watch - ios

I run a Parse query in my iOS app TableViewController.m.
I need to ask the iOS app for that query data from my WatchKit extension InterfaceController.m
How would I go about this using openParentApplication(_:reply:) + handleWatchKitExtensionRequest(_:reply:)?
TableViewController.m (iOS)
- (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];
});
}
}];
}
AppDelegate.m (iOS)
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void(^)(NSDictionary *replyInfo))reply {
NSString * request = [userInfo objectForKey:#"requestString"];
if ([request isEqualToString:#"executeMethodA"]) {
// 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];
});
reply(#{#"success:": #true});
}
}];
}
// Assuming this is where I'd do the reply?
// Not sure what would go here for the reply though?
reply(#{#"success:": #false});
}
InterfaceController.m (WatchKit)
NSString *requestString = [NSString stringWithFormat:#"executeMethodA"]; // This string is arbitrary, just must match here and at the iPhone side of the implementation.
NSDictionary *applicationData = [[NSDictionary alloc] initWithObjects:#[requestString] forKeys:#[#"theRequestString"]];
[WKInterfaceController openParentApplication:applicationData reply:^(NSDictionary *replyInfo, NSError *error) {
// What would I put here?
NSLog(#"\nReply info: %#\nError: %#",replyInfo, error);
}];
I'm using Objective-C. Will add any extra info needed, thanks!

Make the Parse query in your AppDelegate method and package it in an NSDictionary and call reply(queryDict); The replyInfo dictionary in your InterfaceController will be populated with queryDict.

Related

Combind parse queries and add to seperate arrays

How can I combine multiple Parse Queries?
I want to query the column sclink and songTitle from parse.com then add each to its own array.
Also how to save query locally and call it? IF else statment or something:
NSMutableArray *trackList = [[NSMutableArray alloc] init];
PFQuery *queryTracks = [PFQuery queryWithClassName:#"liveRadioPL"];
NSArray *objects = [queryTracks findObjects]; // Online PFQuery results
[PFObject pinAllInBackground:objects];
[queryTracks selectKeys:#[#"scLink"]];
[queryTracks findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
totalTracks = (int)objects.count;
NSLog(#"Successfully retrieved %lu Tracks.", (unsigned long)objects.count);
// Do something with the found objects
for (PFObject *object in objects) {
[trackList addObject:[NSString stringWithFormat:#"%#", [object objectForKey:#"scLink"]]];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
trackListArray = trackList;
NSMutableArray *trackTitles = [[NSMutableArray alloc] init];
PFQuery *queryTitles = [PFQuery queryWithClassName:#"liveRadioPL"];
NSArray *objectsTitle = [queryTitles findObjects]; // Online PFQuery results
[PFObject pinAllInBackground:objects];
[queryTracks selectKeys:#[#"songTitle"]];
[queryTracks findObjectsInBackgroundWithBlock:^(NSArray *objectsTitle, NSError *error) {
if (!error) {
// The find succeeded.
totalTitles = (int)objectsTitle.count;
NSLog(#"Successfully retrieved %lu Titles.", (unsigned long)objectsTitle.count);
// Do something with the found objects
for (PFObject *object in objects) {
[trackTitles addObject:[NSString stringWithFormat:#"%#", [object objectForKey:#"songTitle"]]];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
I'm not sure your logic really makes sense - you're using 4 API requests when all you need is 1 API request. Also, Jacob is right, you're filling an array from a background thread and as a result the main thread will see it as empty.
I think I understand what you're trying to do - try this
PFQuery *queryTracks = [PFQuery queryWithClassName:#"liveRadioPL"];
// use includeKey if slink and songTitle are pointers to other Parse classes
// from the context of your question you probably don't need to use includeKey
[queryTracks includeKey:"scLink"];
[queryTracks includeKey:"songTitle"];
NSArray *objects = [queryTracks findObjects];
NSMutableArray* scLinks = [[NSMutableArray alloc] init];
NSMutableArray* songTitles = [[NSMutableArray alloc] init];
for (PFObject* object in objects) {
[scLinks addObject:object[#"scLink"]];
[songTitles addObject:object[#"songTitles"]];
}
I hope this helps, good luck!

`UIApplicationDelegate` to `WKInterfaceController` data pass

Any ideas on how to pass this data from my iOS AppDelegate.m to my WatchKit InterfaceController.m?
I run a Parse query in my iOS AppDelegate.m
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void(^)(NSDictionary *replyInfo))reply {
NSString * request = [userInfo objectForKey:#"requestString"];
if ([request isEqualToString:#"executeMethodA"]) {
// 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);
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"dispatch");
});
reply(#{#"localMatchup": localMatchup});
}
else {
reply(#{#"error": error.description});
}
}];
}
}
Happy to post any extra code just ask, thanks!
There is a reply block in your handleWatchKitExtensionRequest method, run it with your data in a dict when you finish your query.
reply(#{#"localMatchup": localMatchup});
i think you can call handleWatchKitExtensionRequest method

MBProgressHUD not showing from another class

I'm getting values from Parse Cloud by pressing a button. The code for getting the data data from Parse is in another class, but when I try to show the MBProgessHUD from that class it doesn't do anything.
No errors either. However, if I do all in the same class, it works. Not sure how to display the progressHUD from another class on a specific view which is open at that time.
- (IBAction)testWeather:(id)sender {
Reports * obje2 = [[Reports alloc]init];
[obje2 startGetting];
}
// in reports class
-(void) startGetting {
Names= [[NSMutableArray alloc] init];
Latitude= [[NSMutableArray alloc] init];
Longitude= [[NSMutableArray alloc] init];
[Names removeAllObjects];
[Latitude removeAllObjects];
[Longitude removeAllObjects];
NSUserDefaults * standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *CountyName = [standardUserDefaults stringForKey:#"CurrentlySelectedCounty"];
PFQuery *query = [PFQuery queryWithClassName:#"Reports"];
[query whereKey:#"County" equalTo:#"Universal"];
//
NSInteger countTotal= [query countObjects];
NSString *totalVals = [NSString stringWithFormat: #"%d", (int)countTotal];
[[NSUserDefaults standardUserDefaults] setObject:totalVals forKey:#"NumberOfSwamps"];
//
NSString * storyboardName = #"Main_iPhone";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController * vc = [storyboard instantiateViewControllerWithIdentifier:#"browsePage"];
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:vc.view animated:YES];
hud.mode = MBProgressHUDModeIndeterminate;
hud.labelText = #"Loading Reports";
[hud show:YES];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
[hud hide:YES];
if (!error) {
for (PFObject *obj in objects) {
NSString *LastName = [obj objectForKey:#"Name"] ;
NSString *Lat = [obj objectForKey:#"Latitude"] ;
NSString *Lon = [obj objectForKey:#"Longitude"] ;
// add values to array
[Names addObject:LastName];
[Latitude addObject:Lat];
[Longitude addObject:Lon];
[self getResults];
}
}
else{
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
Trying another way...but this doesn't work either...even though HUD is running from the original class.
browse.m,
if (myInt == 8){
NSLog(#"\n \n Pressed the refresh icon for reports");
[self removeAllAnnotations];
[standardUserDefaults setInteger:1 forKey:#"HUD_Switch"]; // to make sure switching on
[standardUserDefaults synchronize];
[self HUDSwitcher];
Reports * obje2 = [[Reports alloc]init];
[obje2 startGetting];
}
-(void) HUDSwitcher{
NSUserDefaults * standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSInteger myInt = [standardUserDefaults integerForKey:#"HUD_Switch"]; // 0 for switched off .... 1 for switched on
NSString * storyboardName = #"Main_iPhone";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController * vc = [storyboard instantiateViewControllerWithIdentifier:#"browsePage"];
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:vc.view animated:YES];
hud.mode = MBProgressHUDModeIndeterminate;
hud.labelText = #"Testing";
[hud show:YES];
if (myInt==0) {
[hud hide:YES];
}
}
reports.m
[standardUserDefaults setInteger:1 forKey:#"HUD_Switch"]; // to switch on the HUD value
browsePage * obje2 = [[browsePage alloc]init];
[obje2 HUDSwitcher];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
[standardUserDefaults setInteger:0 forKey:#"HUD_Switch"];
[standardUserDefaults synchronize];
browsePage * obje2 = [[browsePage alloc]init];
[obje2 HUDSwitcher];
if (!error) {
for (PFObject *obj in objects) {
NSString *LastName = [obj objectForKey:#"Name"] ;
NSString *Lat = [obj objectForKey:#"Latitude"] ;
NSString *Lon = [obj objectForKey:#"Longitude"] ;
// add values to array
[Names addObject:LastName];
[Latitude addObject:Lat];
[Longitude addObject:Lon];
[self getResults];
}
}
else{
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
When you instantiate the new UIViewController vc, it is not in the current view stack, so if you display a progressHUD on its view it won't appear on the screen.
You should display the progressHUD from the view of the initial viewController.
One way to solve this would be with delegation like this:
- (IBAction)testWeather:(id)sender {
self.hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeIndeterminate;
hud.labelText = #"Loading Reports";
[hud show:YES];
Reports * obje2 = [[Reports alloc]init];
[obje2 startGettingWithDelegate:self];
}
- (void)reports:(Reports*)report didFinishGetting
{
[self.hud hide:YES];
}
In yourViewController interface in the .h file add this:
#property (nonatomic, strong) MBProgressHUD *hud;
In Reports Class
-(void) startGettingWithDelegate:id<yourProtocol> delegate {
Names= [[NSMutableArray alloc] init];
Latitude= [[NSMutableArray alloc] init];
Longitude= [[NSMutableArray alloc] init];
[Names removeAllObjects];
[Latitude removeAllObjects];
[Longitude removeAllObjects];
NSUserDefaults * standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *CountyName = [standardUserDefaults stringForKey:#"CurrentlySelectedCounty"];
PFQuery *query = [PFQuery queryWithClassName:#"Reports"];
[query whereKey:#"County" equalTo:#"Universal"];
//
NSInteger countTotal= [query countObjects];
NSString *totalVals = [NSString stringWithFormat: #"%d", (int)countTotal];
[[NSUserDefaults standardUserDefaults] setObject:totalVals forKey:#"NumberOfSwamps"];
//
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
// Inform Delegate that finished loading
[delegate reports:self didFinishLoading];
if (!error) {
for (PFObject *obj in objects) {
NSString *LastName = [obj objectForKey:#"Name"] ;
NSString *Lat = [obj objectForKey:#"Latitude"] ;
NSString *Lon = [obj objectForKey:#"Longitude"] ;
// add values to array
[Names addObject:LastName];
[Latitude addObject:Lat];
[Longitude addObject:Lon];
[self getResults];
}
} else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
To do this right you should create a #protocol in Reports.h and make you viewController conform to it.
In Reports.h
#protocol ReportsProtocol
- (void)reports:(Reports*) finishedLoading;
#end
#interface ...
.
.
.
In yourViewController.h
#interface YourViewController : UIViewController <ReportsProtocol>
.
.
.
Another solution can be using blocks. Its a little more complicated but cleaner.

Returning a single key value from an array with multiple identical values?

I have an array of objects(images) with key values of #"titleLabel" stored on a backend server(parse). What I am trying to do is display the list of titles in a pickerView but I only want to display ONE title for every group of #"titleLabels" whose keys match. For example: if I have five objects(images) with titleLabel key: 'Spring Break' I only want to display one instance of the title 'Spring Break' and not all five. The code I have written is my best amateur shot at solving it but my NSLog for 'titles array count' is returning a value of 1 and when I log the value I get all of the titles again.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
PFQuery *query = [PFQuery queryWithClassName:#"Images"];
[query whereKey:#"recipientIds" equalTo:[[PFUser currentUser] objectId]];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
else {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for(id obj in self.objectsArray){
PFObject *key = [self.objectsArray valueForKey:#"titleLabel"];
if(![dict objectForKey:key]){
[dict setValue:obj forKey:key];
}
}
for (id key in dict) {
NSLog(#"key: %#, value: %# \n", key, [dict objectForKey:key]);
NSLog(#"Objects array is %d", [self.objectsArray count]);
NSLog(#"Titles array is %d", [self.titlesArray count]);
}
[self.pickerView reloadComponent:0];
}
}];
And here is where I define my keys in a separate controller:
PFObject *image = [PFObject objectWithClassName:#"Images"];
[image setObject:self.releaseDate forKey:#"releaseDate"];
[image setObject:file forKey:#"file"];
[image setObject:fileType forKey:#"fileType"];
[image setObject:title forKey:#"titleLabel"];
[image setObject:deadline forKey:#"deadline"];
[image setObject:self.recipients forKey:#"recipientIds"];
[image setObject:[[PFUser currentUser] objectId] forKey:#"senderId"];
[image setObject:[[PFUser currentUser] username] forKey:#"senderName"];
[image saveInBackground];
PFObject *object = [self.objectsArray valueForKey:#"titleLabel"];
if(object != [self.objectsArray valueForKey:#"titleLabel"]){
self.titlesArray = [self.titlesArray arrayByAddingObject:object];
}
you are checking if the object is equal to what you just assigned. Also, you should be using a NSMutableArray but if you dont care, i dont care too. :) Saying that, i guess your else loop should look like this
self.objectsArray = objects;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for(id obj in self.objectsArray){
PFObject *key = [self.objectsArray valueForKey:#"titleLabel"];
if(![dict objectForKey:key]){
[dict setValue:obj forKey:key];
}
}
for (id key in dict) {
NSLog(#"key: %#, value: %# \n", key, [dict objectForKey:key]);
}

pulling a value from NSMutableDictionary

Here's my code for returning a unique value for identical keys in a dictionary. Right now, in my log, my "objects array:" is 6 (3 sets of (2 objects with identical keys)), and my "dictionary:" returns values for 1 object from each set (3 unique values). In my 'for' statement:
for (id key in dict)
{
self.titlesArray = [NSMutableArray arrayWithObject:dict];
NSLog(#"titles: %#", self.titlesArray);
self.titlesArray = [[NSMutableArray alloc] initWithObjects:[dict valueForKey:key] ,nil];
NSLog(#"titles: %#", self.titlesArray);
}
The first log prints out the three unique values AND keys. The second prints only a single value for a single key (which is what I want.. but I need all three key values) So my problem now is that I am unable to pull a key for each unique value from the dictionary and add it to my titlesArray.
for (id key in dict)
{
self.titlesArray = [NSMutableArray arrayWithObject:dict];
self.titlesArray = [[NSMutableArray alloc] initWithObjects:[dict valueForKey:key] ,nil];
code isn't quite right.
PFQuery *query = [PFQuery queryWithClassName:#"Images"];
[query whereKey:#"recipientIds" equalTo:[[PFUser currentUser] objectId]];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
else {
// found messages!
self.objectsArray = objects;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for(id obj in self.objectsArray){
PFObject *key = [obj valueForKey:#"titleLabel"];
if(![dict objectForKey:key]){
[dict setValue:key forKey:[obj valueForKey:#"titleLabel"]];
}
}
for (id key in dict) {
self.titlesArray = [NSMutableArray arrayWithObject:dict];
NSLog(#"titles: %#", self.titlesArray);
self.titlesArray = [[NSMutableArray alloc] initWithObjects:[dict valueForKey:key] ,nil];
NSLog(#"titles: %#", self.titlesArray);
}
NSLog(#"dictionary: %#", dict);
NSLog(#"Objects array is %d", [self.objectsArray count]);
[self.pickerView reloadComponent:0];
it looks like there is some type error in line
PFObject *key = [self.objectsArray valueForKey:#"titleLabel"];
it should be
PFObject *key = [obj valueForKey:#"titleLabel"];
It's happening in this line, isn't it:
if(![dict objectForKey:#"titleLabel"]){
[dict setValue:obj forKey:key];
}
}
You are setting "obj" as a value, no problem there, but then you are using "key" which is a PFObject, but NSDictionary requires a NSString for the key.
If PFObject contains a NSString property that you want to use, you can pass that in. For example, if PFObject has an NSString property called "name" you could call this:
if(![dict objectForKey:#"titleLabel"]) {
[dict setValue:obj forKey:key.name];
}
}
The relevant thing to notice is the types of the parameters when NSMutableDictionary defines this method, namely the (NSString*):
- (void)setValue:(id)value forKey:(NSString *)key
How does your PFObject look like. Does it have strings in it?. According to your question you already know that you can't pass a PFObject as key for dictionary. If your object is some what like this
interface PFObject : NSObject
{
NSString *keyString;
......
.Some other variables
}
Then you should be using it like this to set it as key
PFObject *key = [self.objectsArray valueForKey:#"titleLabel"];
if(![dict objectForKey:#"titleLabel"]){
[dict setValue:obj forKey:[key valueForKey#"titleLabel"]];
}
Here is the code I found to work. It takes the array and sorts through the keys to return only unique values for a specific key:
PFQuery *query = [PFQuery queryWithClassName:#"Images"];
[query whereKey:#"recipientIds" equalTo:[[PFUser currentUser] objectId]];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
else {
// found messages!
self.objectsArray = objects;
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for(id obj in self.objectsArray){
PFObject *key = [obj valueForKey:#"titleLabel"];
if(![dict objectForKey:key]){
[dict setValue:key forKey:[obj valueForKey:#"titleLabel"]];
}
}
for (id key in dict) {
self.titlesArray = [NSMutableArray arrayWithObject:dict];
[self.titlesArray addObject:dict.allKeys];
self.titlesArray = [self.titlesArray objectAtIndex:1];
}
NSLog(#"titles: %#", self.titlesArray);
[self.pickerView reloadComponent:0];

Resources