从UITableViewCell移除NSNotification Observer及CollectionView更新咨询
用NSNotification实现Section Header触发对应Cell内CollectionView行更新的方案
这个场景我之前做类似的电商分类页面时遇到过,用NSNotification来实现确实是个可行的思路,下面给你一步步拆解具体实现:
1. 定义专属的Notification名称
首先要定义一个唯一的通知名称,避免和系统或其他业务的通知冲突:
import UIKit // 全局定义通知名称,方便各方引用 extension NSNotification.Name { static let updateCollectionViewRows = NSNotification.Name(rawValue: "com.yourApp.updateCollectionViewRows") }
2. 在Section Header的按钮点击事件中发送通知
当用户点击Section Header的按钮时,我们需要把当前的section索引通过通知的userInfo传出去,这样接收方才能知道要更新哪个section下的Cell:
// 假设你的Section Header是自定义的UITableViewHeaderFooterView子类 class CustomSectionHeader: UITableViewHeaderFooterView { var section: Int = 0 // 记录当前header所属的section @IBAction func updateButtonTapped(_ sender: UIButton) { // 发送通知,携带section信息 NotificationCenter.default.post( name: .updateCollectionViewRows, object: nil, userInfo: ["targetSection": section] ) } } // 在UITableView的viewForHeaderInSection方法中给header赋值section func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "CustomSectionHeader") as! CustomSectionHeader header.section = section return header }
3. 在包含CollectionView的TableViewCell中监听通知并处理更新
每个TableViewCell需要持有自己所属的section索引,这样收到通知时能判断是否是自己需要更新的,然后同步更新CollectionView的数据源并刷新指定行:
class CustomTableViewCell: UITableViewCell { @IBOutlet weak var collectionView: UICollectionView! var section: Int = 0 // 记录当前cell所属的section // 假设collectionView的数据源是cell自己管理的数组 var collectionData: [String] = [] override func awakeFromNib() { super.awakeFromNib() // 添加通知监听 NotificationCenter.default.addObserver( self, selector: #selector(handleCollectionUpdate(_:)), name: .updateCollectionViewRows, object: nil ) } @objc private func handleCollectionUpdate(_ notification: Notification) { guard let targetSection = notification.userInfo?["targetSection"] as? Int else { return } // 只处理当前cell所属section的更新请求 guard targetSection == section else { return } // 第一步:先更新collectionView的数据源(这里根据你的业务逻辑修改) // 示例:更新前3行的数据 if collectionData.count >= 3 { collectionData[0] = "更新后内容1" collectionData[1] = "更新后内容2" collectionData[2] = "更新后内容3" } // 第二步:刷新collectionView的指定行 let indexPathsToUpdate = [ IndexPath(item: 0, section: 0), IndexPath(item: 1, section: 0), IndexPath(item: 2, section: 0) ] collectionView.performBatchUpdates({ self.collectionView.reloadItems(at: indexPathsToUpdate) }, completion: nil) } // 记得在销毁时移除监听,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) } } // 在UITableView的cellForRowAt方法中给cell赋值section func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell cell.section = indexPath.section // 初始化cell的collectionData等 return cell }
一些需要注意的细节
- 数据源同步:一定要先更新CollectionView的数据源,再调用刷新方法,否则会出现数据和UI不匹配甚至崩溃的情况。
- Section索引准确性:确保Header和Cell的
section属性都被正确赋值,不然会出现更新错Section的问题。 - 内存泄漏:必须在Cell的
deinit方法中移除通知监听,因为NotificationCenter会持有观察者的强引用,不移除会导致Cell无法被释放。
内容的提问来源于stack exchange,提问作者Anita Nagori
相关产品推荐
相关产品推荐

