开发者

iPhone: UITableView not refreshing

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开发者_如何学C *)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.


That didn't quite work for me - but very close. The method I used was -

[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES];


You can also do

[self performSelectorOnMainThread:@selector(reloadTable) withObject:nil waitUntilDone:YES];

so that you can implement a method on the ViewController to do all the UI stuff that you need.

-(void)reloadTable
{
   [self.tableView reloadData];
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜