UITableViewCell 的重用问题。

发布于 2022-08-31 09:18:39 字数 211 浏览 12 评论 0

我每个 cell 里面都有一个 button,我为 button 设置了一个点击响应动作 btn_tapped
btn_tapped 里面我把 sender 转换成 button 对象,并操作它:比如设置为隐藏。但是发现跟它共用同一个内存 button 也隐藏起来了。
有没有什么方法可以拿到 button 并且设置属性又不冲突的?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

旧情勿念 2022-09-07 09:18:39

在复用TableView的时候,一定要从数据源的角度出发

以咱们这个问题为例,比如,我们的tableView数据源是timelineArray,保存着一个timeline列表。假如Button是“赞”这个按钮的话,我们之所以要展示这个“赞”按钮,是因为当前这条timeline中的isLiked(是否被赞)属性为NO.所以这样写:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{     
    BtnTableViewCell *cell = (BtnTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"BtnTableViewCell"];

    NSDictionary* timeline = [self.timelines objectAtIndex:indexPath.row];
    BOOL isLiked = [[timeline objectForKey:@"isLiked"] boolValue];
    //tableViewCell的样式是和数据源有关的,所以我们是根据数据源来确定样式。为了阅读方便写成下面这样,其实是可以写成一行:cell.likeButton.hidden = !isLiked;
    if (isLiked) {           
        cell.likeButton.hidden = YES;
    }else{            
        cell.likeButton.hidden = NO;
    }
    //我们最好再给button再加一个tag,方便标识之后点击的时候确定点击了哪条timeline
    cell.likeButton.tag = indexPath.row;
    return cell;
}

因为在滑动tableview时,就是通过cellForRowAtIndexPath来复用cell的,所以数据源的改变,cell的样式也会改变。同时,我们进行任何操作时,本来就会更新数据源的最新状态,这是最正确的做法。

- (void)btn_tapped:(id)sender
{
    if(![sender isKindOfClass:[UIButton class]){
        return;
    }
    UIButton *btn = (UIButton*)sender;
    //通过tag来获取到timeline的index
    NSInteger row = btn.tag;

    //【1】立即隐藏该按钮;
    btn.hidden = YES;        
    //【2】标记数据源,例如保存这条消息已经被赞过了,方便接下来复用cell时识别
    NSMutableDictionary *timeline = [self.timelines objectAtIndex:row];
    [timeline setObject:[[NSNumber alloc] initWithBool:YES] forKey:@"isLiked"];
}
慈悲佛祖 2022-09-07 09:18:39

你应该在点击之后把是否显示按钮的状态存起来,再reload TableView, 在tablveiw获取cell的代理方法时通过你存的是否要显示的状态来显示或者隐藏按钮

压抑⊿情绪 2022-09-07 09:18:39

因为没有具体的代码,所以以下是我觉得可以解决的方案。
猜测问题:cell的重用机制造成了公用内存。
解决问题应该从重用方式上考虑。(可以自己搜索如何解决重用,应该有3种方法)
主要的解决办法就是CellIdentifier定义成不同的。
--------
我写了一个小例子

原始状态:

图片描述

点击btn后的状态(隐藏一个btn)

图片描述

目录文件:

图片描述


table代码

主要代码在-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;如下:

cpp-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //定义不同的CellIdentifier
    NSString *CellIdentifier = [NSString stringWithFormat:@"cell%i%i",indexPath.section,indexPath.row];
    //绑定CellIdentifier
    BtnTableViewCell *cell = (BtnTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"BtnTableViewCell" owner:self options:nil];
        cell = [topLevelObjects objectAtIndex:0];
    }
    return cell;
}

cell中的代码:

BtnTableViewCell.h中:

cpp@interface BtnTableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UIButton *cellBtn;
@property (weak, nonatomic) IBOutlet UILabel *cellTitle;
@end

BtnTableViewCell.m文件代码:

cpp- (void)awakeFromNib {
    [self.cellBtn addTarget:self action:@selector(btn_tapped:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];
}

- (void)btn_tapped:(id)sender
{
    UIButton *btn = sender;
    btn.hidden = YES;
}

这样实现的效果就可以点击一个btn,让其隐藏,而且还可以尽量减少内存的使用。
不知道是否解决你的问题,如有问题,请继续提问。

不知道为什么就是排不好版面了。

瑾夏年华 2022-09-07 09:18:39

一楼说得好。即然是复用,那就应该把他从脑子里列出来。它只是装载数据的容器,一切属性都应该取决于他所装载的数据。所以变动的时候首先想到的应该是变动它的数据源,然后再刷新容器。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文