1

I want to use KVO to be notified when the number of selected cells in a UICollectionView changes. When I tried to subclass UICollectionView and add a new property nSelectedCells, I ran into a problem when trying to add the logic that updates nSelectedCells. There are too many places where the selected cells count can change:

  • Programmatically - View: deselectItemAtIndexPath, selectItemAtIndexPath, reloadData, ...
  • UI - Controller: didDeselectItemAtIndexPath, didSelectItemAtIndexPath
  • More?

What would be the best way to keep track of this value. Preferably from within the UICollectionView subclass.

Xyand
  • 4,470
  • 4
  • 36
  • 63
  • Incrementing/decrementing in `collectionView:didSelectItemAtIndexPath:`, `collectionView:didDeelectItemAtIndexPath:` should cover all places IMO. – Drux Jun 29 '14 at 21:17
  • @Drux These methods aren't automatically called if the cell is selected/deselected programmatically. – nhgrif Jun 29 '14 at 21:23

2 Answers2

0

UICollectionViewCell has a selected property. You could override the setter for this method, as it's the only thing guaranteed to be called when a cell's selection status is changed.

Perhaps subclass a UICollectionView with a property to keep a counter of selected cells and register for notifications fired by your UICollectionViewCell subclasses in setSelected: based on whether the cells was selected or deselected.

As a note, just because setSelected: was called doesn't mean the selection status has changed.

- (void)setSelected:(BOOL)selected {
    if (super.selected != selected) {
        if (selected) {
            // cell was unselected and became selected, increase counter
        } else {
            // cell was selected and become unselected, decrease counter
        }
    }
    super.selected = selected;
}
nhgrif
  • 61,578
  • 25
  • 134
  • 173
  • `[[NSNotificationCenter defaultCenter] postNotificationName:@"CellSelected" object:self];` and `@"CellDeselected"`. Just register for these notifications in your collection view (and unregister in `dealloc`). `NSNotificationCenter` is plenty easy and there are plenty of quick examples available on StackOverflow/Google search. http://stackoverflow.com/questions/2676398/how-to-post-and-receive-an-notification – nhgrif Jun 29 '14 at 21:46
  • Well that sounds like too much. To keep track of CollectionView state I have to go through its subviews + global notifications. There goes encapsulation. I hoped there is a cleaner way. thanks. – Xyand Jun 29 '14 at 21:56
  • Yeah. The unfortunate thing is though, a cell can actually be selected without going through the collection view at all, nevermind all the ways to do it while going through the collection view. All anyone needs is a reference to the cell, and then it's easy as `cell.selected = YES;` – nhgrif Jun 29 '14 at 21:58
  • But the collection still has to have a way of keeping track of `indexPathsForSelectedItems`. If it doesn't then using `cell.selected = YES` is not a proper usage of a `UICollectionViewCell`. – Xyand Jun 29 '14 at 22:03
  • It doesn't have to keep track though. It can easily iterate through all of the index paths and add them to the array it's going to return if the cell's `selected` property is `YES`. – nhgrif Jun 30 '14 at 00:13
  • I don't think it can. AFAIK, cells get reused once they go off screen. – Xyand Jun 30 '14 at 05:06
0

use a NSMutableSet to track selected cell's index path, when select a cell, add its indexPath to set; deselect a cell, remove its index path from set.

The collection view calls these methods only when the user successfully selects/deselect an item in the collection view. It does not call the method when you programmatically set the selection/deselection.

@property (nonatomic) NSMutableSet *selectedCellIndexPathsSet;

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    //do some things.
    [self.selectedCellIndexPathsSet addObject:indexPath];
}

- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
    //do some thing.
    [self.selectedCellIndexPathsSet removeObject:indexPath];
}
seedante
  • 300
  • 4
  • 10
  • @Xyand Yes, you could directly add object to NSMutableSet or remove object from it, but why you do this? If you meant" - Programmatically - View: deselectItemAtIndexPath, selectItemAtIndexPath, reloadData", these don't work on the NSMutableSet. – seedante May 12 '15 at 01:07