UITableView cells strangely disappearing

coming to you from team Marko

We are havign an incredible strange problem in which our table view cells, which normally appear like so:

Appear like such:

Upon review, the bug seems to happen when you put the iPhone to sleep, then reopen the app and going to the uiviewcontroller in which the tableview is placed. Somehow this makes it so that cellForRowAtIndexPath no longer gets called, even though the delegate and dataources are still set to self. Our sections and row numbers are still normal and we are able to scroll down on the tableview. But since cellForRowAtIndexPath isn't getting called, the tableviewcells are hidden.

Here is our tableview setup (I took out stuff from this huge file that has nothing to do with the tableview:

//
//  SPHomeViewController.m
//  Spek

@interface SPHomeViewController () <UITableViewDataSource, UITableViewDelegate, MKMapViewDelegate, SPCreationViewDelegate, UIAlertViewDelegate, CLLocationManagerDelegate>
@property (nonatomic, strong) UITableView* tableView;
@property (nonatomic, strong) NSMutableArray* tableDatasource;
@property (nonatomic, strong) NSMutableArray* datasource;
@property (nonatomic, strong) NSMutableArray* friendsDatasource;
@property (nonatomic, strong) UISegmentedControl* userFilterSegment;
@property (nonatomic) BOOL isLoadingData;
@end

@implementation SPHomeViewController

@synthesize datasource = _datasource;
@synthesize friendsDatasource = _friendsDatasource;
@synthesize tableDatasource = _tableDatasource;



- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    //[[SPLocationManager locationManager] startUpdatingLocationForSig];
    [self setNeedsStatusBarAppearanceUpdate];
    self.view.backgroundColor = [UIColor colorWithRed:230.0f/255.0f green:230.0f/255.0f blue:230.0f/255.0f alpha:1.0];
    self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - kTopBarHeight)];
    self.tableView.separatorColor = [UIColor clearColor];
    self.tableView.backgroundColor = [UIColor clearColor];
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    [self.view addSubview:self.tableView];


}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.

    if (self.creationView.center.y > self.view.frame.size.height) {
        self.creationView = nil;
    }
    NSLog(@"Mem warning");
}


//****************************************
//****************************************
#pragma mark - UITableViewDelegate/DataSource
//****************************************
//****************************************

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"INDEX PATH ROW: %d AND SECTION: %d", indexPath.row, indexPath.section);
    if (indexPath.section == 0) {
        UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"SPMapCellSpace"];
        cell.backgroundColor = [UIColor clearColor];
        cell.backgroundView = [[UIView alloc] init];
        cell.selectedBackgroundView = [[UIView alloc] init];
        return cell;
    } else if (indexPath.section == self.tableDatasource.count + 1) {
        UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"SPBottomCellSpace"];
        cell.backgroundColor = [UIColor clearColor];
        cell.backgroundView = [[UIView alloc] init];
        cell.selectedBackgroundView = [[UIView alloc] init];

        return cell;
    }
    SPMark* mark = self.tableDatasource[indexPath.section - 1];
    NSString* reuseId = [SPHomeViewController cellIdentifierFromData:mark];
    SPTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:reuseId];
    if (cell == nil) {
        cell = [SPTableViewCell cellFromMark:mark reuseID:reuseId];
        [cell updateView:YES];
    }
    [cell addDataToCell:mark];
    if (indexPath.section >= self.tableDatasource.count - 2 && !self.isLoadingData && self.pageNumber != -1) {
        self.fetchNextPage = YES;  // When the scrollview stops it will load more data if available.
    }

    return cell;
}

- (unsigned int)getPageNumber {
    return (self.userFilterSegment.selectedSegmentIndex == 0) ? self.pageNumber : self.friendsPageNumber;
}

- (void)setCurrentPageNumber:(unsigned int)page {
    if (self.userFilterSegment.selectedSegmentIndex == 0) {
        self.pageNumber = page;
    } else {
        self.friendsPageNumber = page;
    }
}

- (void)incrementCurrentPageNumber {
    if (self.userFilterSegment.selectedSegmentIndex == 0) {
        self.pageNumber++;
    } else {
        self.friendsPageNumber++;
    }
}

// Every cell has a section header so this should be equal to the number of speks returned from the server
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    NSLog(@"section count is: %d",self.tableDatasource.count + 2 );
    return self.tableDatasource.count + 2;  // Add two because the mapview needs to go on the top and extra spacing at the bottom.
}

// There is a section for every cell, so there is only one cell per section
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 1;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0) {
        return kMapHeight+2;
    } else if (indexPath.section == self.tableDatasource.count + 1) {
        return kExtraSpaceBelowHomeView;
    }
    SPMark* mark = self.tableDatasource[indexPath.section - 1];
    return [SPTableViewCell cellHeightForMark:mark];
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0 || indexPath.section == self.tableDatasource.count + 1) {
        cell.backgroundColor = [UIColor clearColor];
    }
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0 || indexPath.section == self.tableDatasource.count + 1)
        return;
    SPMark* mark = self.datasource[indexPath.section - 1 ];
    SPMarkViewController* markVC = [SPMarkViewController withMark:mark];
    [markVC displayData];
    [self.navigationController pushViewController:markVC animated:YES];
}

-(void)reloadTableview {
    [self.tableView setDelegate:self];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.tableView reloadData];
        [self.tableView setNeedsDisplay];
    });
}

- (void)showNoItems {
    if (self.tableDatasource.count == 0 && self.accuracyBad == NO) {
        self.opaqueIcon.hidden = NO;
        self.noItems.hidden = NO;
        self.beTheFirst.hidden = NO;
        self.downArrow.hidden = NO;
        self.noItemsBackround.hidden = NO;
        [self.view bringSubviewToFront:self.noItemsBackround];
        [self.view bringSubviewToFront:self.downArrow];
        [self.view bringSubviewToFront:self.beTheFirst];
        [self.view bringSubviewToFront:self.noItems];
        [self.view bringSubviewToFront:self.opaqueIcon];

    }
}

- (void)showTableView {
    if (self.tableDatasource.count != 0) {
        self.noItems.hidden = YES;
        self.beTheFirst.hidden = YES;
        self.downArrow.hidden = YES;
        self.noItemsBackround.hidden = YES;
        self.opaqueIcon.hidden = YES;

        [self.view sendSubviewToBack:self.noItemsBackround];
        [self.view sendSubviewToBack:self.downArrow];
        [self.view sendSubviewToBack:self.beTheFirst];
        [self.view sendSubviewToBack:self.noItems];
        [self.view sendSubviewToBack:self.opaqueIcon];
    }
}

//****************************************
//****************************************
#pragma mark - Setters/Getters
//****************************************
//****************************************

- (NSMutableArray*)datasource {
    if (!_datasource) {
        _datasource = [NSMutableArray array];
        if (!self.firstLoad) {
            [self loadDataForPagination:NO];
        }
    }
    return _datasource;
}

- (NSMutableArray*)friendsDatasource {
    if (!_friendsDatasource) {
        _friendsDatasource = [NSMutableArray array];
        if (!self.firstLoad) {
            [self loadDataForPagination:NO];
        }
    }
    return _friendsDatasource;
}

- (NSMutableArray*)tableDatasource {
    if (!_tableDatasource) {
        _tableDatasource = (self.userFilterSegment.selectedSegmentIndex == 0) ? self.datasource : self.friendsDatasource;
    }
    return _tableDatasource;
}

- (SPCreationView*)creationView {
    if (!_creationView) {
        UIView* window = [SPUtils getAppDelegate].window;
        CGSize viewSize = window.frame.size;
        CGRect startFrame = CGRectMake(0, viewSize.height, [SPUtils screenWidth], [SPUtils screenHeight]);
        _creationView = [SPCreationView creationView:startFrame delegate:self];
        [window insertSubview:_creationView belowSubview:self.creationButton];
        _creationView.frame = startFrame;
    }
    return _creationView;
}

- (void)setTableDatasource:(NSMutableArray *)tableDatasource {
    _tableDatasource = tableDatasource;
    [self preFetchImages];
    dispatch_async(dispatch_get_main_queue(), ^{
        if(_tableDatasource == nil || _tableDatasource.count == 0) {
            [self showNoItems];
        } else {
            [self showTableView];
        }
        [self reloadTableview];
    });
}

- (void)setDatasource:(NSMutableArray *)datasource {
    _datasource = datasource;
}

- (void)setFriendsDatasource:(NSMutableArray *)friendsDatasource {
    _friendsDatasource = friendsDatasource;
}


@end

Lastly, if you think it has something to do with our delegate, we don't touch the view controller there, so I don't see how that could be a problem. Maybe a memory issue or a background thread issue?

Answers


That's a lot of code, and it's possible the problem could be in your custom SPTableViewCell class and not even in what you've provided.

To speed things up, when you reproduce the problem go into the debugger and dump the view hierarchy. You can do this by calling [self.view recursiveDescription] on your view controller. This will cause the entire subview hierarchy to be printed to the console, which will let you see what's going on with your cells that should - but aren't - displaying. Post the output here if it's not giving you any joy.

But, what is even weirder is that the tableview is still there and it is not a subview problem because you can still scroll:

It may well still be a subview problem - the tableview gets the height of the cells from a separate call, so thats independent of the cells themselves. Try printing out the hierarchy to see what's going on.


The problem was too many background threads going on at once. When we stopped trying to prefetch images, the issue went away.


Need Your Help

Should I stick to the Open Source, or its time to explore the .net world

c# java php .net

I have been developing professionally websites/applications for almost 5 years, using PHP (Zend Framework) with Oracle/MySQL.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.