I have read many topics about UITableViews not refreshing on iPhone, but couldn't find anything matching my situation, so I'm asking for help.
In my class, which extends UIViewController, I have a TableView and an 'ElementList' (which is a wrapper for NSMutableArray) used as data source.
A separate thread adds a new Element to the array via the 'updateList:' method. When this happens, I want the tableView to be refreshed automatically, but this doesn't happen.
By debugging my app, I can see that 'cellForRowAtIndexPath' is never called and I can't figure out why.
I tried to add an Observer, which calls the 'reloadTableView' method (it is actually called) but the tableView is not updated.
This is my code:
#import <UIKit/UIKit.h>
@interface ListViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
UITableView *tableView;
ElementList *elementList; // Wrapper for NSMutableArray
}
// Called by someone else, triggers the whole thing
-(void)updateList:(Element *)element;
// Added out of desperation
-(void)reloadTableView;
@end
@implementation ListViewController
-(void)loadView
{
// Create the TableView
tableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
assert(tableView != nil);
tableView.delegate = self;
tableView.dataSource = self;
[tableView reloadData];
self.view = tableView;
// Added out of desperation
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadTableView) name:@"UpdatedListNotification" object:nil];
}
-(void)reloadTableView
{
// Try anything
[tableView reloadData];
[tableView setNeedsLayout];
[tableView setNeedsDisplay];
[tableView reloadData];
[self.view setNeedsLayout];
[self.view setNeedsDisplay];
}
// Called by someone else, triggers the whole thing
-(void)updateList:(Element *)element
{
assert(element != nil);
[elementList addElement:element];
[element release];
// Notify the observer, which should update its table view
[[NSNotificationCenter defaultCenter] postNotificationName:@"UpdatedListNotification" object:self];
}
// TableView Delegate protocol
- (void)tableView:(UITableView *)table didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Element *selected_element = [elementList getElementAtIndex:indexPath.row];
if (selected_element == nil)
{
NSLog(@"ERROR: Selected an invalid element");
return;
}
[table deselectRowAtIndexPath:indexPath animated:YES];
NSLog(@"Selected %@", selected_element.name);
}
// TableView Data Source protocol
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [elementList count];
}
- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [table dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Set the cell label
cell.textLabel.text = [[elementList getElementAtIndex:indexPath.row] name];
cell.textLabel.frame = cell.bounds;
cell.textLabel.textAlignment = UITextAlignmentLeft;
return cell;
}
@end
Any help is greatly appreciated, thank you.
Notifications are executed in the same thread as the caller. Updating the UI should really be done in the main thread, so you should call -reloadData on the main thread:
-(void)updateList:(Element *)element
{
assert(element != nil);
[elementList addElement:element];
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil];
}
Also note that you shouldn't release an object that you don't own. So don't call [element release] in your -updateList method. The release should be called by the caller of the function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With