Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show custom label when no data available for tableView

The app in question has an ability for users to mark items as favourite. When the user has no favourites saved, I'd like to notify them of the fact (mostly I hate the idea of a blank tableView).

My numberOfRowsInSection is zero when there are no items the user has marked as favourite. I'd like to set cell.textLabel.text = @"You have no favourites" but when there are no items for the table cellForRowAtIndexPath is not called.

I could test numberOfRowsInSection to give a result when it encounters a 0 and then test for 1 row in cellForRowAtIndexPath and then insert the custom text but then what if they only have one favourite?

UPDATE

I tried implementing the idea I had above, and recommended below, but perhaps I'm not doing it right, probably due to the fact that it's a fetchedResultsController with the delegate methods to update the table when a change occurs.

I get this error when I delete the cell when there is but one cell in the table:

*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1447.6.4/UITableView.m:976 Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted). with userInfo (null)

and when there are no cells to be displayed in the first place it crashes with:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[_PFBatchFaultingArray objectAtIndex:]: index (0) beyond bounds (0)'

Here is the relevant code:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    id <NSFetchedResultsSectionInfo> sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];

    if ([sectionInfo numberOfObjects]==0) {
        return 1;
    } else {
        return [sectionInfo numberOfObjects];
    }
} 

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {

if ([[_fetchedResultsController sections] objectAtIndex:0]==0) {
    cell.textLabel.text = @"You have no favorites";
} else {
    Shows *show = [_fetchedResultsController objectAtIndexPath:indexPath];

    cell.textLabel.text = show.ShowsToSerials.serialName;
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%@", show.showTitle];
}
}
like image 902
Michael Morrison Avatar asked Jan 30 '11 01:01

Michael Morrison


2 Answers

1) In my own iOS apps, I create a subview with a UILabel in it, saying "No Results" When numberOfSectionsInTableView is zero, I add the subview to the tableview. When it is != zero, I remove it. This of course requires maintaining the subview in memory as a retained object, so that you can remove it.

2) If you want to make one cell as you somewhat mentioned: When numberOfSectionsInTableView is zero, return 1. Then, in numberOfRowsInSection return 1 as well. In cellForRowAtIndexPath, check both numberOfSectionsInTableView and numberOfRowsInSection, and if they SHOULD be zero (after all you returned 1), then display whatever message.

Solution 1 requires maintaining a variable to hold the subview, but is shorter and cleaner code, and I believe is less CPU intensive (not that either will cause any significant performance issues).

Edit to include code: It was actually a little different than I thought, but basically the same. There are obviously things in here that are to be changed to fit your code and taste.

(Make sure to declare UIView *nomatchesView; in .h)

- (void)viewDidLoad{

        nomatchesView = [[UIView alloc] initWithFrame:self.view.frame];
        nomatchesView.backgroundColor = [UIColor clearColor];

        UILabel *matchesLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0,320,320)];
        matchesLabel.font = [UIFont boldSystemFontOfSize:18];
        matchesLabel.minimumFontSize = 12.0f;
        matchesLabel.numberOfLines = 1;
        matchesLabel.lineBreakMode = UILineBreakModeWordWrap;
        matchesLabel.shadowColor = [UIColor lightTextColor];
        matchesLabel.textColor = [UIColor darkGrayColor];
        matchesLabel.shadowOffset = CGSizeMake(0, 1);
        matchesLabel.backgroundColor = [UIColor clearColor];
        matchesLabel.textAlignment =  UITextAlignmentCenter;

        //Here is the text for when there are no results
        matchesLabel.text = @"No Matches";


        nomatchesView.hidden = YES;
        [nomatchesView addSubview:matchesLabel];
        [self.tableView insertSubview:nomatchesView belowSubview:self.tableView];
    }



    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        //If there is no table data, unhide the "No matches" view
        if([data count] == 0 ){
        nomatchesView.hidden = NO;
        } else {
        nomatchesView.hidden = YES;
        }

        return [data count];
    }
like image 77
Daniel Amitay Avatar answered Sep 27 '22 23:09

Daniel Amitay


What I personally would do is the following. As you said yourself, in the method numberOfRowsInSection you should check the count of your tableView datasource, if its 0 you should return 1 in order to display the 1 cell ou want.

Then in cellForRowAtIndexPath you should check the count again, if it returns 0 you know that the table view is trying to draw your "You currently have no favorites" and you can set the text.

like image 38
Antwan van Houdt Avatar answered Sep 27 '22 22:09

Antwan van Houdt