Make sure you also set the sender
(ie the button that was pressed) to selected too, or reload the collection view once after updating your model.
Update: This answer has been edited and updated after a discussion in chat.
There isn't a need for an iVar
(or @property
) for _addFavouriteButton
in your view controller, the button variable should just be a local variable in the scope of the collectionView:cellForItemAtIndexPath:object:
method - lets start by fixing that method first
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
NSLog(@"cellForItemAtIndexPath");
// other cell info here deleted to make things clearer
// Create a local variable for your button - this saves a bit of typing in the rest
// of the method. You can also use dot notation as its a property
UIButton *favouriteButton = cell.addFavouriteButton;
BOOL objectFavourited = [object[@"favourite"] boolValue];
NSLog(@"Setting selected? %@", objectFavourited ? @"YES" : @"NO");
favouriteButton.selected = objectFavourited;
// You should set the title directly on the button (as per the docs -
// https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIButton_Class/UIButton/UIButton.html#//apple_ref/occ/instp/UIButton/titleLabel),
// you shouldn't touch titleLabel except for styling
// However you only used the title for seeing which object the favourite button tap was for,
// so I've commented it out
// [favouriteButton setTitle:[object objectId] forState:UIControlStateNormal];
[favouriteButton addTarget:_thisController action:@selector(addFavouriteButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
Now the buttons target method. Here you should be doing the following: updating your model, changing the button state and then saving the model. If the model successfully saves do your users care - no not really! If however the save fails, then the user needs to know, and the button and the model need to be reverted to their previous state.
I'm pretty sure that if the save fails, the object will be in the same state as before you attempted the save - with the favourite
property set to YES
. Even if it doesn't, setting it back to NO
wouldn't really matter anyway.
The best way to get the indexPath
of the item that the had its button pressed is to use a similar method to the one in this answer. Its the perfect way to work out the index path, no need for horrible tags!
Now we have the index path of the item, you don't need to query for that specific object - we get get it directly by using objectAtIndexPath:
.
- (void)addFavouriteButtonTapped:(UIButton *)button
{
// Method adapted for a collection view from the above answer
CGPoint hitPoint = [button convertPoint:CGPointZero toView:self.collectionView];
NSIndexPath *hitIndex = [self.collectionView indexPathForItemAtPoint:hitPoint];
// Now get the object for this index
PFObject *object = [self objectAtIndexPath:hitIndex];
NSLog(@"add to favourites button tapped %ld - %@", (long)hitIndex.item, [object objectId]);
// Now update the model
object[@"favourite"] = @YES;
// And the button state
button.selected = YES;
// Now save the model to parse
[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!succeeded) {
// Reset the object back to its previous state
object[@"favourite"] = @NO;
// Reload the item to reflect the changes in the model
[self.collectionView reloadItemsAtIndexPaths:@[hitIndex]];
// Only bother the user if something bad happened
[[[UIAlertView alloc] initWithTitle:@"Oops!"
message:@"There was a problem please try again later"
delegate:self
cancelButtonTitle:@"Dismiss"
otherButtonTitles:nil] show];
}
}];
}
You could reload the collection view, but as you've updated the view in that method there isn't really any need.
However, you should reload the collection view if the save failed as the button might now be being used for a different item in the collection view!