You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift动态UITableView如何删除行?删除后出现空白行

解决UITableView显示符合通讯录条件用户时出现空白行的问题

嘿,我来帮你搞定这个问题!你现在的做法是在cellForRowAt方法里判断用户是否在通讯录中,然后尝试删除不符合条件的行,但这种方式其实踩了UITableView数据源逻辑的坑——这也是为什么会出现空白行的原因。

问题根源分析

  • 你的numberOfRowsInSection仍然返回原始users数组的长度,哪怕你删除了某一行,数据源的长度没更新,TableView还是会渲染对应数量的cell,那些被你“跳过”的位置就会变成空白行。
  • 在cellForRowAt里调用deleteRows和reloadData是非常危险的,会触发TableView的重新布局,很容易造成循环调用或者布局异常。

正确解决方案:提前过滤数据源

正确的思路应该是提前筛选出符合条件的用户,而不是在渲染cell的时候临时处理。具体步骤如下:

  1. 定义一个新数组存储符合条件的用户
// 假设你的用户模型是User类型,在类里添加这个属性
var filteredUsers: [User] = []
  1. 在合适的时机(比如视图加载完成、通讯录数据更新时)执行过滤逻辑
// 调用你的通讯录查询方法,过滤出电话号码存在的用户
filteredUsers = users.filter { user in
    guard let phoneNumber = user.phoneNumber else {
        // 没有电话号码的直接排除
        return false
    }
    return searchForContactUsingPhoneNumber(phoneNumber: phoneNumber)
}
// 过滤完成后刷新TableView
tableView.reloadData()
  1. 修改TableView的数据源方法,使用过滤后的数组
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // 返回过滤后数组的长度,这样TableView只会渲染符合条件的行数
    return filteredUsers.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! UserCell
    let user = filteredUsers[indexPath.row]
    
    // 直接配置cell即可,不需要再判断是否在通讯录中
    cell.textLabel?.text = user.name
    cell.detailTextLabel?.text = user.phoneNumber
    cell.backgroundColor = UIColor(r: 35, g: 35, b: 35)
    cell.textLabel?.textColor = UIColor.white
    cell.detailTextLabel?.textColor = UIColor.white
    
    if let profileImageUrl = user.profileImageUrl {
        cell.profileImageView.loadImageUsingCacheWithUrlString(profileImageUrl)
    } else {
        // 如果没有头像,建议设置默认图,而不是删除行
        cell.profileImageView.image = UIImage(named: "default-avatar")
    }
    
    return cell
}

额外优化:处理通讯录动态变化

如果用户在App运行过程中修改了通讯录(比如添加/删除联系人),可以在viewWillAppear里重新执行过滤逻辑,保证数据实时更新:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // 重新过滤数据并刷新
    filteredUsers = users.filter { user in
        guard let phoneNumber = user.phoneNumber else { return false }
        return searchForContactUsingPhoneNumber(phoneNumber: phoneNumber)
    }
    tableView.reloadData()
}

内容的提问来源于stack exchange,提问作者Danil Onishenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:09:03