What is causing this logic error? - objective-c

Here is my code and here is the output... I do not understand why my if statement above the log is allowing this to happen...This if statement that is nested inside of the for loop should not allow output whenever the fullname is the same the description...
Firebase *firebase = [[Firebase alloc] initWithUrl:[NSString stringWithFormat:#"%#/Recent", FIREBASE]];
FQuery *query = [[firebase queryOrderedByChild:#"groupId"] queryEqualToValue:groupId];
[query observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
//Is group
if ([snapshot.value[#"type"] isEqual: #"group"]){
self.title = snapshot.value[#"description"];
}
//Is individual
else{
NSString *senderId = snapshot.value[#"userId"];
PFQuery *query = [PFQuery queryWithClassName:PF_USER_CLASS_NAME];
[query whereKey:#"objectId" equalTo:senderId];
query.limit = 1;
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// Do something with the found objects
for (PFObject *object in objects) {
NSString *userName = [[PFUser currentUser]fullname];
if (object[#"fullname"] != userName){
self.title = object[#"fullname"];
NSLog(#"You're talking to: %#", object[#"fullname"]);
NSLog(#"Logged in user: %#", userName);
}
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
}];
Heres the log as well
2016-03-12 18:48:09.844 Gibr[34128:1436940] You're talking to: Testerten
2016-03-12 18:48:09.844 Gibr[34128:1436940] Logged in user: Travis Tubbs
2016-03-12 18:48:09.845 Gibr[34128:1436940] You're talking to: Travis Tubbs
2016-03-12 18:48:09.845 Gibr[34128:1436940] Logged in user: Travis Tubbs

The problem that you are using != to compare two strings. But that's not what it's for; it's for comparing objects. The two string variables are not the same object; they are two different objects, two different variables.
If you want to know whether two string variables have the same value as strings, use isEqualToString:.
if (![object[#"fullname"] isEqualToString: userName])

Related

Parse: Query to change labels text

I can currently query a parse class, but can't figure out how to change a labels text if the returned values match the query. I am relatively new to objective C and Parse so my knowledge on the subject is little. My query looks like this (with the text of what i'm trying to achieve underneath).
PFQuery *FTQ0 = [PFQuery queryWithClassName:#"Class1"];
[FTQ0 whereKey:#"Location" equalTo:#"The Shop"];
//Label.text = query (object?)
Thanks in advance.
Here is a solution. You have to be careful though, because there might be many objects that have key Location and equal to The Shop. This is why parse is returning an array of objects. In this case, I pick the first object in the array and display it.
PFQuery *query = [PFQuery queryWithClassName:#"Class1"];
[query whereKey:#"Location" equalTo:#"The Shop"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
Label.text = [NSString stringWithFormat:#"%#", [[objects firstObject] objectForKey:#"WHATEVER YOU WANT TO DISPLAY EX. NAME, LOCATION..."]]
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
For more information please visit https://parse.com/docs/ios/guide
Something like this :
PFQuery *query = [PFQuery queryWithClassName:#"Class1"];
[query whereKey:#"Location" equalTo:#"The Shop"];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error && object) {
// Do your stuff
Label.text = [[object objectForKey:#"YOUR KEY"] stringValue];
} else {
// Error or null object
}
}];
In this example the query return only the first object.
Thanks so much for your quick and helpful response! This was an issue that was troubling me allot! The code provided works!
Thanks!

Getting 'This query has an outstanding network connection.'

I'm getting 'This query has an outstanding network connection.'
I know only one query is allowed at time and I think that's what I'm doing here but apparently not..
retrieveFromParse is at viewDidLoad.
-(void) retrieveFromParse{
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
[query whereKey:#"photo" equalTo:[PFObject objectWithoutDataWithClassName:#"photoObject" objectId:self.currentObjectID]];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", (int)objects.count);
// Do something with the found objects
for (PFObject *object in objects) {
NSLog(#"%#", object.objectId);
self.commentArray = [object objectForKey:#"comment"];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
// If no objects are loaded in memory, we look to the cache
// first to fill the table and then subsequently do a query
// against the network.
if ([self.objects count] == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
}
- (id)initWithStyle:(UITableViewStyle)style currentObjectID:(NSString*) currentObjectID {
self = [super initWithStyle:style];
if (self) {
self.currentObjectID = currentObjectID;
self.parseClassName = #"extra";
self.pullToRefreshEnabled = YES;
self.paginationEnabled = NO;
self.objectsPerPage = 25;
}
return self;
}
The problem is here:
if ([self.objects count] == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
You're calling that after you make the call in the background. In other words, you are trying to modify a query that is currently being made while it's being made in the background - triggering the error. Try this instead:
-(void) retrieveFromParse{
PFQuery *query = [PFQuery queryWithClassName:self.parseClassName];
[query whereKey:#"photo" equalTo:[PFObject objectWithoutDataWithClassName:#"photoObject" objectId:self.currentObjectID]];
[query orderByDescending:#"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", (int)objects.count);
// Do something with the found objects
for (PFObject *object in objects) {
NSLog(#"%#", object.objectId);
self.commentArray = [object objectForKey:#"comment"];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
// If no objects are loaded in memory, we look to the cache
// first to fill the table and then subsequently do a query
// against the network.
if ([self.objects count] == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
}];
}

Checking for Existing Friend Requests in Parse

I am creating my own friend network using parse and want to check to see if a friend request has been sent from one user to another. However, it seems that when I query my parse database it takes some time to receive the information and therefore acts as if a friend request had never been made between two users even though the relationship exists already.
//This is the method to test to see if the request has already been sent
-(int) testForFriendRequestBetween: (NSString *) ID1 and: (NSString *) ID2
{
NSString *user1 = ID1;
NSString *user2 = ID2;
PFQuery *query1 = [PFQuery queryWithClassName:#"friendRequest"];
[query1 whereKey:#"requestFrom" equalTo:user1];
[query1 whereKey:#"requestTo" equalTo:user2];
[query1 findObjectsInBackgroundWithBlock:^(NSArray *objects1, NSError *error) {
if (error)
{
a = 0;
NSLog(#"Error with query");
}
else
{
a = objects1.count;
NSLog(#"%i", a);
}}];
return a;
}
//This is where the user types in an email address to search for a friend and I test to see if request already exists
- (IBAction)sendRequest:(id)sender
{
PFUser *currentUser = [PFUser currentUser];
NSString *myID = currentUser.objectId;
//Look in email column and search whatever was typed into the texfield
PFQuery *query = [PFQuery queryWithClassName:#"_User"];
[query whereKey:#"email" equalTo: _typeEmail.text];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error)
{
//If the user was found
if (!error)
{
//Create a string that reads the unique ID
NSString *friendID = object.objectId;
//Test to see if request already exists
int test1 = [self testForFriendRequestBetween:myID and:friendID];
int test2 = [self testForFriendRequestBetween:friendID and:myID];
if(test1+test2 == 0)
{
NSLog(#"%i", test1+test2);
//Save request to new row
PFObject *request = [PFObject objectWithClassName:#"friendRequest"];
request[#"requestFrom"] = myID;
request[#"requestTo"] = friendID;
request[#"status"] = #"pending";
[request saveInBackground];
//Update label
_requestLabel.text = #"Friend Request Sent";
} else
{
_requestLabel.text = #"Request Already Sent";
}
}
//If user was not found
else
{
//Update label
_requestLabel.text = #"Friend Is Not Registered";
}
}
];
}
The output of this in the console is:
2014-07-07 13:14:25.559 SignIn[11363:70b] 0
2014-07-07 13:14:25.667 SignIn[11363:70b] 14
2014-07-07 13:14:25.730 SignIn[11363:70b] 2
This means that it is first reporting that test1 + test2 = 0. But then it runs the first method and says that the value of test1 is 14 and the value of test2 is 2! Any help would be much appreciated.
Your implementation of testForFriendRequestBetween has a serious bug. You return a value that does not have a valid value. If you make an asynchronous request, like you do with findObjectsInBackgroundWithBlock:, you can't return the result of that call synchronously (i.e. by using return a. Instead, your method should have a callback block with a parameter that contains the data you receive from the query. You call that callback inside the query completion block.
Here's a simple example based on your code. As you see, all the results are processed in the callback blocks. This is the only correct way when you get the data using async calls.
- (void)testForFriendRequestBetween:(NSString *)ID1 and:(NSString *)ID2 callback:(void (^)(NSArray *results))completion {
// configure the query object, etc.
[query1 findObjectsInBackgroundWithBlock:^(NSArray *objects1, NSError *error) {
if(!error) {
// now you can send the query results back to the caller!
callback(objects1);
}
}
}
- (IBAction)sendRequest:(id)sender
{
// set up query, etc.
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error)
{
//If the user was found
if (!error)
{
[self testForFriendRequestBetween:myID and:friendID callback:^(NSArray *results) {
if(results.count == 0) {
// do stuff
}
}];
}
}
}

Strange issue with Parse.com with key not being included

I'm having an issue very similar to this one
Basically I'm using Parse.com to load some objects, which have PFUser pointers, and then I'm also using includeKey to include those PFUsers, here's the code...
PFQuery *query = [PFQuery queryWithClassName:#"GameVillageObject"];
[query whereKey:#"region" equalTo:[NSNumber numberWithInt:region]];
[query includeKey:#"pfUser"];
query.limit = 100;
[sharedInstance requestSentWithDesc:#"Get all village objects in region"];
[query findObjectsInBackgroundWithBlock:^(NSArray *PUObjects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d village objects from server.", PUObjects.count);
if(PUObjects.count > 0)
{
villageObjects = PUObjects;
for (int i=0; i<[villageObjects count]; i++)
{
PFObject *villageItem = [villageObjects objectAtIndex:i];
PFUser *user = [villageItem objectForKey:#"pfUser"];
NSString *userName = [NSString stringWithFormat:#"%#",[user objectForKey:#"username"]];
NSLog(#"User name is: %#.", userName);
}
[self setupVillageList];
[sharedInstance centerImage:marketItemsContainer xChoice:YES yChoice:NO];
}
} else {
// Log details of the failure
NSLog(#"Getting village objects Error: %# %#", error, [error userInfo]);
}
}];
Now for some reason, everynow and again, maybe 1 time out of 10, the game is crashing, with this error
Key "username" has no data. Call fetchIfNeeded before getting its
value.
Although I can't tell if it's crashing when I try to use "username" above, or a little later when I try to use "username" but either way, I don't get why most of the time it has no problem including those extra objects and then a few times it doesn't. Any ideas?
It sounds as though the associated user is not being loaded, but may be cached in most instances (and thus available). I can think of two ways to resolve this.
1) Call fetchIfNeeded as suggested by the error message:
PFQuery *query = [PFQuery queryWithClassName:#"GameVillageObject"];
[query whereKey:#"region" equalTo:[NSNumber numberWithInt:region]];
[query includeKey:#"pfUser"];
...
PFObject *villageItem = [villageObjects objectAtIndex:i];
PFUser *user = [villageItem objectForKey:#"pfUser"];
[user fetchIfNeeded];
NSString *userName = [NSString stringWithFormat:#"%#",[user objectForKey:#"username"]];
NSLog(#"User name is: %#.", userName);
2) Specify pfUser.username in the includeKey: call
[query whereKey:#"region" equalTo:[NSNumber numberWithInt:region]];
[query includeKey:#"pfUser.username"];
query.limit = 100;
...
This should tell Parse to load username when the query is executed.
I had this same problem.
Here is what I did:
call fetchIfNeeded on the pointer.
ex.
[someObject.user fetchIfNeeded]
this will get the information about the user that you need.
If you need a PFFile from the user object you can do the following.
//if you run this code in cellForRowAtIndexPath and want to update the profile image for the user you can do the following.
User *user = (User *)someObject.user;
[user.profileImage getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:data];
cell.userProfileImage.image = image;
}else{
NSLog(#"Print error!!! %#", error.localizedDescription);
}
}];

Better way to retrieve nested array in a PFQuery in Parse.com?

I am using Parse.com to store data for an iOS app. The code below successfully retrieves all values in a nested array belonging to a PFObject "game". However, if I need to query for another array (at the same level as "winners" (say "losers") i cannot get it to work, and not all the values in the array losers gets populated. I suppose i could do them all on the main thread and not try to nest the fetches (nested blocks) but i'm wondering if:
1) Is the way i'm storing my data prohibiting me from using Parse's built in query/fetch functionality properly? Data stored as:
PFObject * newGame = [PFObject objectWithClassName:#"Game"];
NSArray * winner = [NSArray arrayWithObjects:[_allPlayersPFDictionary objectForKey:[playerData objectAtIndex:0]], [playerData objectAtIndex:1], nil];
[_gamePF addObject:winner forKey:#"winners"];
2) Is there a better, cleaner way to do the query and get ALL the values of all nested arrays of data in a query? Again, winners is not a PFObject, but is an array of array of PFObject of 2 different types ([PFObject fetchAll:(NSArray *)winnersArray] does not work, because all objects in the Array must be of the same 'type' of PFObject). I store it this way because each winning player has another PFObject (1 to many) "powers" associated with them.
Here is the query that works but i can't figure out how to add "losers" to it and properly populate all data in the background.
PFQuery * gamesQuery = [PFQuery queryWithClassName:#"Game"];
[gamesQuery orderByDescending:#"createdAt"];
gamesQuery.limit = 30;
[gamesQuery findObjectsInBackgroundWithBlock:^(NSArray * theGames, NSError * error) {
if (error) {
NSLog(#"ERROR: There was an error with the Query to get Games!");
} else {
for (PFObject * aGame in theGames) {
for (NSArray * aWinner in [aGame objectForKey:#"winners"]) {
[[aWinner objectAtIndex:0] fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (error) {
NSLog(#"ERROR: There was an error with the Query to get Player in winnersArray!");
} else {
[PFObject fetchAllIfNeededInBackground:[aWinner objectAtIndex:1] block:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"ERROR: There was an error with the Query to get Powers in winnersArray!");
} else {
[_gamesPF addObject:aGame];
NSLog(#"Games from viewDidLoad %#", _gamesPF);
[_tableView reloadData];
}
}];
}
}];
}
}
}
}];
Well... i feel kinda stupid. Definitely much easier to use Parse in an object oriented manner for the data model. Was able to easily solve it by remodeling the data to be:
Game (PFObject *) has:
--> winners { (PFObject *), (PFObject *), ..., nil }
--> losers { (PFObject *), (PFObject *), ..., nil }
where a winner is created as:
[testWinner1 addObject:power1 forKey:#"power"];
[testWinner1 addObject:power2 forKey:#"power"];
[testWinner1 addObject:[_playerPFDictionary objectForKey:#"Tom"] forKey:#"player"];
Which then makes the query much easier and involves only one background block like so:
PFQuery * gameQuery = [PFQuery queryWithClassName:#"TestGame"];
[gameQuery includeKey:#"winners.player"];
[gameQuery includeKey:#"winners.power"];
[gameQuery includeKey:#"losers.player"];
[gameQuery includeKey:#"losers.power"];
[gameQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"failed");
} else {
NSLog(#"testGame: %#", [objects objectAtIndex:0]);
}
}];