为啥 tableView(_: cellForRowAt indexPath:) 被调用这么多次导致一个奇怪的 UIButton 错误?
Posted
技术标签:
【中文标题】为啥 tableView(_: cellForRowAt indexPath:) 被调用这么多次导致一个奇怪的 UIButton 错误?【英文标题】:Why is tableView(_: cellForRowAt indexPath:) called so many times leading to a weird UIButton bug?为什么 tableView(_: cellForRowAt indexPath:) 被调用这么多次导致一个奇怪的 UIButton 错误? 【发布时间】:2017-04-13 01:37:00 【问题描述】:我只是为了好玩而制作了一个简单的项目,但我的程序中有一个非常奇怪的错误。
这个函数返回 29 是正确的,但是当我的表格视图被实例化时它被调用了 3 次。
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
print("ingredient count: \(Sushi.ingredients.count)")
return Sushi.ingredients.count
我认为 (_: numberOfRowsInSection:)
被调用 3 次是导致这段代码执行的元素数量几乎是成分数组中元素数量的三倍的原因。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
guard let cell = tableView.dequeueReusableCell(withIdentifier: "IngredientCell", for: indexPath) as? IngredientCell
else
return UITableViewCell(style: .default, reuseIdentifier: nil)
cell.ingredientLabel.text = Sushi.ingredients[indexPath.row]
print("ingredient label text: \(cell.ingredientLabel.text)\nindex path: \(indexPath)\ncell index: \(cell.index)\nbutton tag: \(cell.selectButton.tag)\nindex path row: \(indexPath.row)\ncell object: \(cell)\n")
return cell
只要正确列出数组中的所有成分,表格视图就会被适当地填充。但是,tableView 的每一行都是一个原型单元格,其中包含一个 UILabel、一个 UIButton 和一个 UIImage。当按下按钮时,该按钮的文本和颜色会发生变化,而且表格视图单元格中的每十三个按钮也会发生变化。
本课程适用于我的单个单元格
class IngredientCell: UITableViewCell
public var userSelected = false
public var index: Int = 0
@IBOutlet weak var picture: UIImageView!
@IBOutlet weak var selectButton: UIButton!
@IBOutlet weak var ingredientLabel: UILabel!
//This method is called when a button is pressed
@IBAction func selectIngredient(_ sender: UIButton)
if userSelected == false
userSelected = true
selectButton.setTitleColor(.red, for: .normal)
selectButton.setTitle("Remove", for: .normal)
else
userSelected = false
selectButton.setTitle("Select", for: .normal)
selectButton.setTitleColor(.blue, for: .normal)
我决定使用打印语句进行调试,看看我是否能弄清楚到底发生了什么,我发现numberOfRowsInSection
被调用了 3 次,cellForRowAtIndexPath
被调用了不同的次数。我不断迭代表格视图,为单元格对象提供相同的内存地址,我想这是导致多个按钮在仅按下一个按钮时发生变化的原因。我的控制台输出证明情节提要中的不同按钮在内存中具有相同的地址。
【问题讨论】:
按下按钮时是否正在刷新表格内容? 一点也不。按下按钮时我唯一要做的就是更改布尔变量并更新按钮的颜色和文本,这会影响其他 1-2 个按钮。 好吧,我不确定你是否知道。但是 UITableView 正在重用您创建的单元格。当您更改单元格 1 中的 UI 元素时,它可能会影响单元格 10,假设单元格 10 使用与单元格 1 相同的实例。 UITableView 不会每次都创建一个新单元格(除非你告诉它这样做)并且新项目会添加到表格中。 我只需要使用静态单元而不是原型吗? 【参考方案1】:抱歉,我只能用 Objective-C 编写。但无论如何,我只是要向你展示这个想法。
仅更新表中单个项目的 UI 内容的一种方法是重新加载该特定单元格。
例如:您的单元格仅包含一个按钮。当您按下特定按钮时,您只想更改该按钮的标题。然后,您所要做的就是创建一个字典,该字典引用表中所有按钮的所有标题,然后在重新加载该特定单元格时将标题设置为该按钮。
你可以这样做:
@interface ViewController ()<UITableViewDelegate, UITableViewDataSource>
@property NSMutableDictionary *buttonTitlesDict;
@end
@implementation ViewController
- (void)viewDidLoad
[super viewDidLoad];
buttonTitles = [[NSMutableDictionary alloc] init];
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
static NSString *identifier = @"SimpleTableItem";
UITableViewCell *tableCell = [tableView dequeueReusableCellWithIdentifier:identifier];
if(tableCell == nil)
tableCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
tableCell.button.title = [_buttonTitles objectForKey:@(indexPath.row)];
tableCell.button.tag = indexPath.row;
//reloads only a specific cell
- (IBAction)updateButton:(id)sender
NSInteger row = [sender tag];
[_buttonTitlesDict setObject:@"changedTitle" forKey:@(row)];
[_tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:row inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
如您所见,我刚刚创建了一个字典,其中包含每个按钮的按钮标题,其中单元格的索引作为参考键。每次我想更新按钮的标题时,每次在 cellForRowAtIndexPath 上加载单元格时,我都会从按钮中获取该标题。请注意,当您滚动表格时,当新单元格出现在您面前时,将调用 cellForRowAtIndexPath。因此,当您滚动时,正确的标题将更新为按钮。
希望这会有所帮助。
【讨论】:
以上是关于为啥 tableView(_: cellForRowAt indexPath:) 被调用这么多次导致一个奇怪的 UIButton 错误?的主要内容,如果未能解决你的问题,请参考以下文章
未调用 alertviewcontroller 中的 tableview 的“cellForRowAtIndexPath”
为啥在将单元格插入带有静态单元格的表格视图时需要 tableView(_:indentationLevelForRowAt:)
使用 UITapGestureRecognizer 检测 UITableViewCell 中 UILabel 的点击事件