I'm trying to update a PFObject that already exists in the cloud by performing a query, adjusting the retrieved object, and then saving it. I initially tried this with the saveInBackgroundWithBlock method, but the block never got called. I moved the save method afterwards, and any code after the save call does not get executed.
I'm running Yosemite with the newest Parse OS X SDK.
-(void)saveCardToCloud:(Card *)card{
if(card.cardID){
PFQuery *cardQuery = [PFQuery queryWithClassName:#"Card"];
[cardQuery whereKey:#"cardID" equalTo:card.cardID];
[cardQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
if ([objects count] > 0) {
PFObject *retrievedObject = [objects firstObject];
retrievedObject[#"lastSeenAt"] = card.lastSeenAt;
if(!retrievedObject[#"firstSeenAt"]){
retrievedObject[#"firstSeenAt"] = card.firstSeenAt;
}
retrievedObject[#"officeCheckIns"] = card.officeCheckIns;
retrievedObject[#"shopCheckIns"] = card.shopCheckIns;
[retrievedObject save];
NSLog(#"SAVED IT");
[retrievedObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if(!error){
NSLog(#"Updated existing card");
}else{
NSLog(#"Failed to update existing card: %#", error);
}
}];
}
}
}];
}
}
I was setting one of the keys on the PFObject to nil, but Parse wasn't throwing an exception. Fix:
if(card.officeCheckIns) retrievedObject[#"officeCheckIns"] = card.officeCheckIns;
if(card.shopCheckIns) retrievedObject[#"shopCheckIns"] = card.shopCheckIns;
Related
Im trying to work with a script thats in objective c i want to make an int i can access throughout view did load to change settings or the viewcontroller but it doesn't work like swift and i get a null out of the pfquery so i tried to make an array and couldn't get anything out of the query with that as well
what is the best way to set up and int variable and set it in the pfquery then use if statements later on
here is some of my code
__block int setting = 0;
PFQuery *query = [PFQuery queryWithClassName:#"test"];
[query whereKey:#"testActive" equalTo:[NSNumber numberWithBool:YES]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %lu scores.", (unsigned long)objects.count);
// Do something with the found objects
for (PFObject *object in objects) {
NSLog(#"%#", object.objectId);
setting = [[object objectForKey:#"testSetting"] intValue];
// When checked in the loop i get all the right data
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
// When checked here i get settings = 0 when it should be 1
if (setting == 0) {
self.segmentedControl.selectedSegmentIndex = 0;
} else if (setting == 1) {
self.segmentedControl.selectedSegmentIndex = 1;
}
if (setting == 3) {
[self.segmentedControl setEnabled:YES];
}else {
[self.segmentedControl setEnabled:NO];
}
But when i check the setting int its always 0 but if i log in the loop is gives me the correct number
thanks for your help
Thanks for your help but i figured it out..
findObjectsInBackgroundWithBlock was not completing before i did the if statements
so i moved the code into a new function which i ran when the PFQuery was completed giving me the correct int
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;
}
}];
}
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
}
}];
}
}
}
I have a PFObject and a few of the keys contain pointers. Sometimes I'm not including these in the original query. How do I fetch these for an existing object? Do I have to form a whole new PFQuery?
The accepted answer is incorrect. The OP said that sometimes the related objects are not included in the original query, and asks if another query is necessary.
includeKey is for use in the original query. If the objects are not included, the correct approach is to use fetchIfNeeded:
https://parse.com/docs/ios/api/Classes/PFObject.html#//api/name/fetchIfNeeded
PFObject *department = user[#"department"];
// If includeKey was not used for department in the original query, department is now only a stub pointing to the actual object.
[department fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) {
NSString *departmentName = department[#"name"];
}];
Use includeKey: on any pointer keys you want included in the query.
PFQuery * query = [PFQuery queryWithClassName:#"SomeParseClass"];
[query includeKey:#"SomePointerKey"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
PFObject * firstOb = objects[0];
PFObject * pointerObject = firstOb[#"SomePointerKey"];
}
}];
If you already have an object, you can fetch the pointer object. If it doesn't have a reference to the object, you would have to stack fetches:
if (ob[#"SomePointerKey"]) {
// ob already has pointer to object
PFObject * pointerOb = ob[#"SomePointerKey"];
[pointerOb fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
// pointerOb ready here!
}
}];
}
else {
// ob is missing pointer data, fetch it!
[ob fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) {
PFObject * pointerOb = object[#"SomePointerKey"];
[pointerOb fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!error) {
// pointerOb ready here!
}
}];
}];
}
I am a bit new to Xcode and Parse and am creating a query in a outlet collection. Everything looks fine except I am getting an error stating "Property 'text' not found on object of type 'id'"... Here is my code that I have:
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
NSLog(#"Successfully retrieved %d scores.", objects.count);
// Do something with the found objects
int i = 0;
for (PFObject *object in objects) {
if (i >= [self.EventTitles count]) break;//to make sure we only write up to the max number of UILabels available in EventTitles
(UILabel *) self.EventTitles[i].text = object.objectId;//I assume the "objectId" property of object is an NSString!
i++;
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
Can anyone help me so I can get this build to not fail?
Change this:
(UILabel *) self.EventTitles[i].text = object.objectId;
to:
[(UILabel *)self.EventTitles[i] setText:object.objectId];