Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UITableView 先 setDelegate: 再 setDataSource: 可能引发 crash #1427

Closed
MoLice opened this issue Aug 10, 2022 · 1 comment
Closed

UITableView 先 setDelegate: 再 setDataSource: 可能引发 crash #1427

MoLice opened this issue Aug 10, 2022 · 1 comment

Comments

@MoLice
Copy link
Collaborator

MoLice commented Aug 10, 2022

背景

考虑以下代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    // ...
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    self.tableView.tableHeaderView = xxx;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 0;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    id sectionData = data[section];// 假定此时 data 为一个 NSArray 实例,但 count 为 0
    return ...;
}

预期会先询问 numberOfSectionsInTableView,得知是0,就不会再继续去询问 numberOfRowsInSection,于是没问题。

但实际上系统会跳过 numberOfSectionsInTableView,直接询问 numberOfRowsInSection,导致此时我们长度为0的数组被访问了一个下标为0的元素,命中 assert,crash。

原因解释

初看这段代码平平无奇,但这里有个前提,系统的 setDelegate: 会自动 reload 一次,而 setDataSource: 却不会 reload。于是实际的时序是:

  1. 先执行 setDelegate:,触发自动 reload,此时 tableView.dataSource 尚未被赋值,所以 numberOfSections 为系统默认值1。
  2. 再执行 setDataSource:,没有自动 reload,tableView 依然认为自己 numberOfSections 为 1。
  3. setTableHeaderView: 会触发 tableView 计算 contentSize,进而触发它询问数据源,由于到此为止依然没人再去 reload,所以 tableView 认为 numberOfSections 是1,所以直接去询问第一个 section 里的 numberOfRowsInSection,但对业务来说此时数据源是空的,于是越界。
@MoLice
Copy link
Collaborator Author

MoLice commented Aug 10, 2022

已发布 4.5.0 修复该问题。

@MoLice MoLice closed this as completed Aug 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant