UIRefreshControl插入UITableView新行后持续旋转且触发失效求助
咱们先拆解你遇到的两个核心问题:添加新帖子后UIRefreshControl无法停止刷新,以及后续下拉时不再触发目标函数。结合你的代码来看,主要有几个关键的问题点,咱们一步步来解决:
1. 改用UITableView原生绑定UIRefreshControl(iOS 10+)
你现在用tableView.addSubview(refresher)的方式添加刷新控件,但从iOS 10开始,UITableView已经原生支持直接通过refreshControl属性绑定刷新控件。这种方式下系统会自动管理控件的层级、布局和状态,比手动添加子视图可靠得多——手动添加很可能导致系统无法正确追踪刷新控件的状态,这也是endRefreshing无效的核心原因之一。
修改viewDidLoad中的代码:
override func viewDidLoad() { super.viewDidLoad() refresher = UIRefreshControl() // 替换addSubview为原生绑定方式 tableView.refreshControl = refresher refresher.addTarget(self, action: #selector(didDragScrollView), for: .valueChanged) // 删掉这行zPosition设置,原生绑定不会出现遮挡问题 // refresher.layer.zPosition = -1 }
2. 确保UI操作在主线程执行
如果你的添加帖子操作是异步完成的,代理方法didAddPost可能会在后台线程触发,而所有UI操作必须在主线程执行。哪怕你说行已经正确插入,也建议把endRefreshing和其他UI更新逻辑包裹在主线程里:
extension FeedViewController: AddPostDelegate { func didAddPost(_ userPost: UserPost) { DispatchQueue.main.async { self.postsWrapper?.posts.insert(PostWrapper(type: PostType.user(userPost)), at: 0) self.tableView.beginUpdates() self.tableView.insertRows(at: [IndexPath(row: 1, section: 0)], with: .automatic) self.tableView.endUpdates() self.refresher.endRefreshing() } } }
3. 移除layer.zPosition = -1的设置
你当初加这行是为了解决iOS 9.2的遮挡问题,但用原生tableView.refreshControl绑定后,系统会自动处理层级关系,不会出现刷新控件跑到表头单元格前面的情况。更重要的是,设置zPosition = -1会让刷新控件处于TableView的底层,导致用户的下拉触摸事件无法传递到它身上——这就是后续下拉不再触发didDragScrollView的直接原因!
4. 验证插入行的IndexPath匹配性(可选)
你把数据插在了数组的第0位,但插入行的IndexPath是row:1,如果你的TableView第0行是固定的表头单元格(比如独立于section header的行),那没问题;但如果不是,这里可能会导致数据和UI的位置不匹配。虽然你说行已正确插入,但还是建议确认一下这个IndexPath是否和数据插入的位置对应,避免潜在的UI异常。
总结修复步骤
- 用
tableView.refreshControl = refresher替代手动添加子视图的方式 - 移除
refresher.layer.zPosition = -1这行代码 - 确保所有UI更新逻辑(包括
endRefreshing)在主线程执行
按照这几步修改后,应该就能解决刷新控件无法停止、以及后续不触发目标函数的问题了。
内容的提问来源于stack exchange,提问作者daredevil1234

