简体   繁体   中英

TableView scrollToRow is blocking the main ui thread

I have a UITableView with about 500 items.

When i call tableView.scrollToRow(at: indexPath, at: .bottom, animated: false) the main UI thread is getting blocked for 3 seconds.

Is there a way to fix this? or is the problem scrolling 500 items?

Thanks


the problem is not with reloadData it was with scrollToRow

From discussion about how to use a table view for chat: We can use a table view which uses a transform to flip the Y coordinate. We then need to do the same for each of the cells so they are not upside down.

The procedure is to build a normal messaging table view where the newest message is on top (instead of bottom). Then put the table view on some superview and invert its coordinate system:

chatContainer?.transform = CGAffineTransform(scaleX: 1.0, y: -1.0)

The cell containing the messages should also have some sort of superview for all the contents which needs to be flipped:

    override func awakeFromNib() {
        super.awakeFromNib()

        containerView?.transform = CGAffineTransform(scaleX: 1.0, y: -1.0)
    }

So the cell is basically flipped twice so it is shown correctly.

You may find an example project here .

Use time profiler to identify where exactly is the issue. The thing is that in general the UITableView performance is not effected by a number of items loaded. The view itself will load as many items as it needs to fill the whole screen.

You may test this by logging a method in a cellForRowAtIndexPath . So I am guessing this method may be the one that is slow. Check how you access the data from it, maybe there is some heavy logic on it. Or the cell layout may be bugged and very slow.

In a general case if you have extremely large amount of data consider using core data and NSFetchedResultsController which is designed specifically for this situations. But still note that loading 500 elements in a table view should work smoothly without any special optimizations.

You should do something like this; If user scroll down from top to bottom of the tableview scrollview delegate method fire its "scrollViewDidScroll" method and detect if user bottom of tableview or not then fetch other data and append your array and reload the tableview. Thats it!

- (void)scrollViewDidScroll:(UIScrollView *)scrollView 
{   
    CGFloat actualPosition = scrollView_.contentOffset.y;
    CGFloat contentHeight = scrollView_.contentSize.height - (someArbitraryNumber);
    if (actualPosition >= contentHeight) {
        [self.newsFeedData_ addObjectsFromArray:self.newsFeedData_];
        [self.tableView reloadData];
     }
}

I'm not 100% sure about this solution, didn't had that problem myself. Maybe just dispatch it?

extension UITableView {

func tableViewScrollToBottom(animated: Bool) {

        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {

            let numberOfSections = self.numberOfSections
            let numberOfRows = self.numberOfRows(inSection: numberOfSections-1)
            if numberOfRows > 0 {
                let indexPath = IndexPath(row: numberOfRows-1, section: (numberOfSections-1))
                self.scrollToRow(at: indexPath, at: UITableViewScrollPosition.bottom, animated: animated)
            }
        }
    }
}

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