简体   繁体   中英

Why does my UITableView lose it's fluidity when I scroll during an asynchronous reload data?

Here is my problem... I'm making an asynchronous call to the service I'm working with, which returns search results back to me. When that's done, it reloads my table, and the async is done. The problem is, when I try scrolling on my table view before the async call is done, the table loses that fluid feeling that all scroll views have. What I mean by this is that when you let go of the scroll, rather than keeping going and slowly stopping, it just halts as soon as you let go. The only way to restore the fluid feeling is to scroll all the way to the top or bottom of the UITableView and a little past, then it's fine.

Here is my code for the async call:

__block NSMutableArray *appendMoreObjects = [[NSMutableArray alloc] init];

    dispatch_async( dispatch_get_main_queue(), ^{

        self.activity.hidden = NO;

        appendMoreObjects = [service search:self.query from:((moreCount * 8)) until:((moreCount * 8) + 8)];

        if( appendMoreObjects == nil )
        {
            //alert view
        }
        else
        {
            [self.allSearchResults addObjectsFromArray:appendMoreObjects];

            [self updateSearchArray];

            self.moreCount += 1;
        }

        self.activity.hidden = YES;
    });

Also, keep in mind that I'm using a custom UITableViewCell. If any other information is needed, please request it and I'll see what I can do. Thank you in advance.

EDIT1: [self updateSearchArray] contains the [tableView reloadData]

EDIT2: I'm testing on an iPod Touch running 4.3.1 (8G4)

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
customCell * cell = (customCell *)[tableView dequeueReusableCellWithIdentifier:@"cell"];

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

if( indexPath.row == [self.searchResults count] && [self.searchResults count] > 0)
{

    UITableViewCell *moreCell = [[[UITableViewCell alloc] initWithFrame:CGRectZero] autorelease];
    moreCell.textLabel.text = @"More";
    moreCell.textLabel.textAlignment = UITextAlignmentCenter;

    return moreCell;
}

if( indexPath.row < [self.searchResults count] )
{
    [cell formatAndInsertData:[self.searchResults objectAtIndex:indexPath.row]];
}

return cell;
}

Solution:

What I actually ended up doing was locking down the table and all UI elements until the call was done. Maybe not the best solution, but it worked none the less.

Calling [tableView reloadData] will reload your ENTIRE table, which is the reason you are seeing the choppy UITableView. It forces all visible cells to refresh, so as you are scrolling, the visible cells are refreshing and repainting themselves. You'll need to reevaluate your strategy for updating the UITableView as you have data coming in to avoid this. You should update individual cells that could be visible that have data that pertain to your updates.

To do this, you will need to use the following methods:

– insertRowsAtIndexPaths:withRowAnimation:

– deleteRowsAtIndexPaths:withRowAnimation:

– reloadRowsAtIndexPaths:withRowAnimation:

The combination of these will allow you to update your table (add/remove rows), as you receive data, and not force the refresh of the entire table.

I would like to see the custom cell, to fully answer your problem.

Also, the cellForRowAtIndexPath: segment of your table controller, to see how you are reusing your cells.

Last, but not least: Which type of device are you testing on? (type and generation)

EDIT:

This part:

if( indexPath.row == [self.searchResults count] && [self.searchResults count] > 0)
{

    UITableViewCell *moreCell = [[[UITableViewCell alloc] initWithFrame:CGRectZero] autorelease];
    moreCell.textLabel.text = @"More";
    moreCell.textLabel.textAlignment = UITextAlignmentCenter;

    return moreCell;
}

looks downright poisonous... Dont have the time to test it right now, but please never add cells within a cell... the tablecontroller will be not only confused, but block out too much memory.

Only use the cellForRowAtIndexPath: for simple things like filling in titles, descriptions and images.

Do your reload logic on the tableview controller, but somewhere safer. The cellForRowAtIndexPath will be loaded every time a cell appears, even if it was just in sight.

make sure you are only reloading table data on main thread. preferably, i use nsinvocation rather than GCD:)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM