我试图滚动到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是正确的)


当前回答

实际上这个解决了我的问题:

-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

NSSet *visibleSections = [NSSet setWithArray:[[tableView indexPathsForVisibleRows] valueForKey:@"section"]];
if (visibleSections) {
    // hide the activityIndicator/Loader
}}

其他回答

当[tableView reloadData]返回时,tableView背后的内部数据结构已经被更新。因此,当方法完成时,您可以安全地滚动到底部。我在自己的应用程序中验证了这一点。rob mayoff的答案被广泛接受,尽管术语也令人困惑,但他在最近的更新中承认了这一点。

如果你的tableView没有滚动到底部,你可能在你没有发布的其他代码中有问题。也许在滚动完成后,您正在更改数据,并且没有重新加载和/或滚动到底部?

添加如下的日志记录,以验证reloadData之后的表数据是否正确。我在一个示例应用程序中有以下代码,它可以完美地工作。

// Change the data source

NSLog(@"Before reload / sections = %d, last row = %d",
      [self.tableView numberOfSections],
      [self.tableView numberOfRowsInSection:[self.tableView numberOfSections]-1]);

[self.tableView reloadData];

NSLog(@"After reload / sections = %d, last row = %d",
      [self.tableView numberOfSections],
      [self.tableView numberOfRowsInSection:[self.tableView numberOfSections]-1]);

[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:[self.tableView numberOfRowsInSection:[self.tableView numberOfSections]-1]-1
                                                          inSection:[self.tableView numberOfSections] - 1]
                      atScrollPosition:UITableViewScrollPositionBottom
                              animated:YES];

上面的dispatch_async(dispatch_get_main_queue())方法不能保证有效。我看到了它的非确定性行为,其中有时系统在完成块之前完成了layoutSubviews和单元格渲染,有时在完成块之后。

这里有一个解决方案,100%适用于我,在iOS 10上。它需要实例化UITableView或UICollectionView作为自定义子类的能力。这是UICollectionView的解决方案,但它对UITableView是完全一样的:

CustomCollectionView.h:

#import <UIKit/UIKit.h>

@interface CustomCollectionView: UICollectionView

- (void)reloadDataWithCompletion:(void (^)(void))completionBlock;

@end

CustomCollectionView.m:

#import "CustomCollectionView.h"

@interface CustomCollectionView ()

@property (nonatomic, copy) void (^reloadDataCompletionBlock)(void);

@end

@implementation CustomCollectionView

- (void)reloadDataWithCompletion:(void (^)(void))completionBlock
{
    self.reloadDataCompletionBlock = completionBlock;
    [self reloadData];
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    if (self.reloadDataCompletionBlock) {
        self.reloadDataCompletionBlock();
        self.reloadDataCompletionBlock = nil;
    }
}

@end

使用示例:

[self.collectionView reloadDataWithCompletion:^{
    // reloadData is guaranteed to have completed
}];

请看这个答案的Swift版本

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

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

[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。

我和泰勒·谢弗有同样的问题。

我在Swift中实现了他的解决方案,它解决了我的问题。

斯威夫特3.0:

final class UITableViewWithReloadCompletion: UITableView {
  private var reloadDataCompletionBlock: (() -> Void)?

  override func layoutSubviews() {
    super.layoutSubviews()

    reloadDataCompletionBlock?()
    reloadDataCompletionBlock = nil
  }


  func reloadDataWithCompletion(completion: @escaping () -> Void) {
    reloadDataCompletionBlock = completion
    self.reloadData()
  }
}

斯威夫特2:

class UITableViewWithReloadCompletion: UITableView {

  var reloadDataCompletionBlock: (() -> Void)?

  override func layoutSubviews() {
    super.layoutSubviews()

    self.reloadDataCompletionBlock?()
    self.reloadDataCompletionBlock = nil
  }

  func reloadDataWithCompletion(completion:() -> Void) {
      reloadDataCompletionBlock = completion
      self.reloadData()
  }
}

使用示例:

tableView.reloadDataWithCompletion() {
 // reloadData is guaranteed to have completed
}