我试图滚动到UITableView的底部后,它完成执行[自我。tableView reloadData]。

我原本有

 [self.tableView reloadData]
 NSIndexPath* indexPath = [NSIndexPath indexPathForRow: ([self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1) inSection: ([self.tableView numberOfSections]-1)];

[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

但后来我读到reloadData是异步的,所以自self以来滚动就没有发生。表视图,自我。tableView numberOfSections和[self.]tableView numberOfRowsinSection都是0。

很奇怪,我用的是:

[self.tableView reloadData];
NSLog(@"Number of Sections %d", [self.tableView numberOfSections]);
NSLog(@"Number of Rows %d", [self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1);

在控制台中,它返回Sections = 1, Row = -1;

当我在cellForRowAtIndexPath做完全相同的nslog时,我得到Sections = 1和Row = 8;(8是正确的)


当前回答

和一个UICollectionView版本,基于kolaworld的答案。

它需要测试。到目前为止,它在iOS 9.2和Xcode 9.2 beta 2上工作,将collectionView滚动到一个索引,作为一个闭包。

extension UICollectionView
{
    /// Calls reloadsData() on self, and ensures that the given closure is
    /// called after reloadData() has been completed.
    ///
    /// Discussion: reloadData() appears to be asynchronous. i.e. the
    /// reloading actually happens during the next layout pass. So, doing
    /// things like scrolling the collectionView immediately after a
    /// call to reloadData() can cause trouble.
    ///
    /// This method uses CATransaction to schedule the closure.

    func reloadDataThenPerform(_ closure: @escaping (() -> Void))
    {
        CATransaction.begin()
            CATransaction.setCompletionBlock(closure)
            self.reloadData()
        CATransaction.commit()
    }
}

用法:

myCollectionView.reloadDataThenPerform {
    myCollectionView.scrollToItem(at: indexPath,
            at: .centeredVertically,
            animated: true)
}

其他回答

和一个UICollectionView版本,基于kolaworld的答案。

它需要测试。到目前为止,它在iOS 9.2和Xcode 9.2 beta 2上工作,将collectionView滚动到一个索引,作为一个闭包。

extension UICollectionView
{
    /// Calls reloadsData() on self, and ensures that the given closure is
    /// called after reloadData() has been completed.
    ///
    /// Discussion: reloadData() appears to be asynchronous. i.e. the
    /// reloading actually happens during the next layout pass. So, doing
    /// things like scrolling the collectionView immediately after a
    /// call to reloadData() can cause trouble.
    ///
    /// This method uses CATransaction to schedule the closure.

    func reloadDataThenPerform(_ closure: @escaping (() -> Void))
    {
        CATransaction.begin()
            CATransaction.setCompletionBlock(closure)
            self.reloadData()
        CATransaction.commit()
    }
}

用法:

myCollectionView.reloadDataThenPerform {
    myCollectionView.scrollToItem(at: indexPath,
            at: .centeredVertically,
            animated: true)
}

迅速:

extension UITableView {
    func reloadData(completion:@escaping ()->()) {
        UIView.animate(withDuration: 0, animations: reloadData)
            { _ in completion() }
    } 
}

// ...somewhere later...

tableView.reloadData {
    print("done")
}

objective - c:

[UIView animateWithDuration:0 animations:^{
    [myTableView reloadData];
} completion:^(BOOL finished) {
    //Do something after that...
}];

试试这个:

tableView.backgroundColor = .black

tableView.reloadData()

DispatchQueue.main.async(execute: {

    tableView.backgroundColor = .green

})

只有在reloadData()函数完成后,tableView的颜色才会从黑色变成绿色。

试试这个方法。它会起作用的。

[tblViewTerms performSelectorOnMainThread:@selector(dataLoadDoneWithLastTermIndex:) withObject:lastTermIndex waitUntilDone:YES];waitUntilDone:YES];

@interface UITableView (TableViewCompletion)

-(void)dataLoadDoneWithLastTermIndex:(NSNumber*)lastTermIndex;

@end

@implementation UITableView(TableViewCompletion)

-(void)dataLoadDoneWithLastTermIndex:(NSNumber*)lastTermIndex
{
    NSLog(@"dataLoadDone");

NSIndexPath* indexPath = [NSIndexPath indexPathForRow: [lastTermIndex integerValue] inSection: 0];

[self selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];

}
@end

我将在表完全加载时执行。

另一个解决方案是你可以子类化UITableView。

如果你在viewDidLoad时重新加载数据,你可以把你的代码放到viewDidLayoutSubviews方法中。但是你应该小心viewDidLayoutSubviews可能会被多次调用。