5
votes

After parsing JSON data in a Data class, I set the UIViewController's NSArray *headlines property in a fillArrays method of the same Data class. In the viewDidAppear method of my UIViewController, I call reloadData on my UITableView. numberOfSectionsInTableView fires and returns 1, then numberOfRowsInSection fires and returns an array count of 4 (for 4 strings in the array). However, control never gets to cellForRowAtIndexPath and I'm having the hardest time understanding why, especially since I have valid sections and rows. The cells are all visible.

I've added the UITableViewDataSource and UITableViewDelegate protocols to the UIViewController interface and set the UITableView's delegate and dataSource to self in viewDidLoad (which also is verified by the row and section count methods being called).

I'm wondering if it has something to with me reinitializing the UIViewController in Data.m in order to set its properties.

In Data.m:

- (void)fillArrays:(NSArray *)jsonObjs {
    NSLog(@"fillArrays");               
    HeadlinesRootViewController *hrvc = [[HeadlinesRootViewController alloc] init];
    hrvc.headlines = [self getJsonValuesForKey:@"headline" inArrayOfObjects:jsonObjs];
    [hrvc viewDidAppear:NO];
}

In ViewController.m:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"viewDidLoad");
    // Table view
    headlineTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 180, self.view.bounds.size.width, 300) style:UITableViewStylePlain];
    [headlineTableView setDelegate:self];
    [headlineTableView setDataSource:self];
    // Temporary
    self.headlines = [[NSMutableArray alloc] initWithObjects:@"headline1", @"headline2", @"headline3", @"headline4", nil];



    [self.view addSubview:headlineTableView];
    self.headlineTableView = headlineTableView;
    [headlineTableView release];
}
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"viewdidappear");
    NSLog(@"headlines: %@", self.headlines); // Returns an array of 4 headlines
    if( [self.headlines count] != 0 ){
        [self.headlineTableView reloadData];
    }
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    NSLog(@"numberOfSectionsInTableView: 1");
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    NSLog(@"numberOfRowsInSection: %d", [self.headlines count]);
    return [self.headlines count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"cellForRowAtIndexPath");
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }

    cell.text = [[NSString alloc] initWithFormat:@"%@", [self.headlines objectAtIndex:indexPath.row]];

    return cell;
}
9
you might want to post some codeconeybeare

9 Answers

4
votes

In fillArrays, you create another view controller - but you never do anything with it or its view, you would never see that view. You would never call viewDidAppear manually either, that happens automatically when a view controllers view is displayed (ONLY in the context of a navigation controller though).

Normally the flow is, you create a view controller and either add that view as a subview of a current view, or push it as a new window via a navigation controller. I'm pretty sure your whole issue is that they table is never added to a view anyone actually sees, so the table calls the other methods but never calls cellForRow because its layoutSubviews code is simply not being called.

4
votes

Have you added your tableView to the view of UIViewController?

It happened to me, and when I added this

[self.view addSubview:table];
[table release];

then cellForRowAtIndexPath started working.

4
votes

For Google's sake:

If tableView:numberOfRowsInSection returns zero for whatever reason tableView:cellForRowAtIndexPath will not get called because there are no rows to call it for.

0
votes

Check to make sure that the tableView delegate and dataSource are pointed to the viewController

0
votes

I cannot see anything wrong with the code as-is, have you verified with breakpoints that cellForRow is never reached (even though I see you have a log statement)?

Also I would try just for a sanity check to return "1" explicitly in rowsInSection, and hardcode a string in the cell you are returning in cellForRow.

If all else fails, create a new table view controller from the XCode templates and put your calls in there - then when that works, work backwards to why your code does not.

Also, it would be good to see your viewDidLoad setup code (add to answer above please).

0
votes

if you're setting the delegate and datasource at viewDidLoad, then that may be the source of your bug. Can you set the datasource and delegate in init?

0
votes

I'm not sure that you add your UITableView as subview to UIViewController.view. This was my approach anyway.

In this approach, I found execution did not get into cellForRowAtIndexPath until I sent UIViewController.view to the back after adding UITableView as subview.

Getting this far was only part of the problem. At this point, it seemed that my other view controllers no longer respond to touch events. I found that when I also add the UITableView as a subview to the rootViewController, all my views got the appropriate touch events.

0
votes

Thank you so much pxl. When I move the UITableView initialization from viewDidLoad to:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil"

it works perfectly when ever I make delete or update some rows the UITableView gets reloded to my UIView.

0
votes

Swift version

Add self.table.layoutIfNeeded() and then self.tableView.reloadData()