1

I have a UITableView which presents elements which were received as xml and then sorted out into sections and rows. I track which elements were displayed on screen using indexPathsForVisibleRows and hold it into NSMutableSet:

@interface MainFeedTableViewController () <UIGestureRecognizerDelegate>
{
    NSMutableSet *viewedCellsIndexPaths;
}
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    ...
    viewedCellsIndexPaths = [[NSMutableSet alloc] init];
    ...
}
- (void) trackVisibleCells {
// create array of currently displayed cells
NSArray *visibleCells = [_mainFeed indexPathsForVisibleRows];


// add cells to viewedCells set
[viewedCellsIndexPaths addObjectsFromArray:visibleCells];


// get unviewed cells count
NSUInteger cellsCount = 0;
NSInteger sections = [_mainFeed numberOfSections];
for (int i = 0; i < sections; i++) {
    cellsCount += [_mainFeed numberOfRowsInSection:i];
}
NSUInteger unViewedCellsCount = cellsCount - [viewedCellsIndexPaths count];


// pass unviewed cells count to cell
if (self.catchupCellDelegate) {
    [self.catchupCellDelegate updateUnreadCellsCount:unViewedCellsCount];
}

and now I want to open a new view that will display only the items that were not yet displayed.

Based on this answer I tried to create another set from the data source and then [allData minusSet:viewedCellsIndexPaths]. Problem is viewedCellsIndexPaths holds IndexPaths, and the data source holds, well, data.

I've tried adding the whole tables' indexPaths to another set inside CellForRowAtIndexPath but that gave me only the visible ones and not the entire table's index paths.

Then I tried to use NSMutableOrderedSet to keep track of the cells that were visible and then call its LastObject to find out which was the last viewed cell and access the data source from that index:

NSIndexPath *lastIndex = (NSIndexPath *)viewedCellsIndexPaths.lastObject;

but I got an exception [__NSSetM lastObject]: unrecognized selector sent to instance 0x2837acb2.

sounds like a bug within the language which I can't figure a way to work around.

My final attempt based on this answer was:

 NSMutableArray *unviewedCellsData = [NSMutableArray arrayWithArray:sectionOrderedFeed];
    for (NSIndexPath *indexPath in viewedCellsIndexPaths) {
        Items *item = [[sectionOrderedFeed objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
        [unviewedCellsData removeObject:item];
    }

But after iteration unViewedCellsData is exactly the same as sectionOrderedFeed.

Any help here?

Yarden
  • 45
  • 6
  • Where are you calling `trackVisibleCells`? – DonMag Apr 30 '20 at 13:47
  • Testing your code, I get `Property 'lastObject' not found on object of type 'NSMutableSet *'`, on `NSIndexPath *lastIndex = (NSIndexPath *)viewedCellsIndexPaths.lastObject;`which is normal (and that's what the crash is saying). – Larme Apr 30 '20 at 14:56
  • @Larme, As I've stated above, I tried to change `viewedCellsIndexPaths` type to `NSOrderedMutableSet` before trying out this line, you've probably missed it. @DonMag `trackVisibleCells` is called right after the table has finished to load up – Yarden May 03 '20 at 10:42

1 Answers1

0

Here's what I did for a quick test:

@interface ViewedCellsTableViewController ()
{
    NSMutableArray *myData;
    NSMutableSet *viewedCellsIndexPaths;
    NSMutableOrderedSet *orderedAllIndexPaths;
}

@end

@implementation ViewedCellsTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // just creating sample data...
    //  6 sections with a few rows in each section
    NSArray *rowsPerSection = @[@3, @5, @4, @8, @6, @7];

    myData = [NSMutableArray new];
    int iSection = 0;
    for (NSNumber *nRows in rowsPerSection) {
        NSMutableArray *aSec = [NSMutableArray new];
        for (int iRow = 0; iRow < [nRows intValue]; iRow++) {
            NSString *s = [NSString stringWithFormat:@"This is sec: %d row:%d", iSection, iRow];
            [aSec addObject:s];
        }
        [myData addObject:aSec];
        ++iSection;
    }

    // initialize ordered set of all index paths
    orderedAllIndexPaths = [NSMutableOrderedSet new];
    iSection = 0;
    for (NSArray *aSec in myData) {
        for (int iRow = 0; iRow < [aSec count]; iRow++) {
            NSIndexPath *p = [NSIndexPath indexPathForRow:iRow inSection:iSection];
            [orderedAllIndexPaths addObject:p];
        }
        ++iSection;
    }

    // init tracking set
    viewedCellsIndexPaths = [NSMutableSet new];

}

Then, when ready to move on...

NSMutableOrderedSet *unViewedCellsIndexPaths = [orderedAllIndexPaths mutableCopy];
[unViewedCellsIndexPaths minusSet:viewedCellsIndexPaths];

NSLog(@"\nViewed:\n%@ \n..", viewedCellsIndexPaths);
NSLog(@"");

NSLog(@"\nUn-Viewed:\n%@ \n..", unViewedCellsIndexPaths);
NSLog(@"");
DonMag
  • 69,424
  • 5
  • 50
  • 86