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

如何从BookDetailViewController更新TableView单元格页码?能否用Notification Center?

问题解答:用Notification Center实现书籍阅读进度更新

完全可以通过Notification Center实现这个需求,下面是具体的实现步骤和代码修改方案:

1. 定义全局通知名称

先定义一个全局的通知标识符,方便两端统一引用:

extension Notification.Name {
    static let updateBookProgress = Notification.Name("UpdateBookProgress")
}

2. 在HomeViewController中注册并处理通知

在viewDidLoad中添加通知监听,同时在控制器销毁时移除监听避免内存泄漏,新增处理通知的方法来更新数据源和表格:

class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SendingBookDataProtocol {

    @IBOutlet weak var addBookButton: UIButton!
    @IBOutlet var tableView: UITableView!
    
    var items = [BookItem]()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView?.delegate = self
        tableView?.dataSource = self

        let nib = UINib(nibName: "BookCell", bundle: nil)
        tableView?.register(nib, forCellReuseIdentifier: "BookCell")
        
        // 注册进度更新通知
        NotificationCenter.default.addObserver(self, selector: #selector(updateBookProgress(_:)), name: .updateBookProgress, object: nil)
    }
    
    deinit {
        // 移除通知监听
        NotificationCenter.default.removeObserver(self)
    }
    
    // 处理进度更新通知
    @objc private func updateBookProgress(_ notification: Notification) {
        guard let userInfo = notification.userInfo,
              let index = userInfo["index"] as? Int,
              let newCurrentPage = userInfo["currentPage"] as? String,
              index < items.count else { return }
        
        // 更新数据源中的页码
        items[index].currentPage = newCurrentPage
        // 仅刷新对应单元格,比全局reload更高效
        tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .automatic)
    }

    // 原有代码保持不变...
    
    // 修改didSelectRowAt,传递书籍在数据源中的索引
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let bookDetailVc = self.storyboard?.instantiateViewController(withIdentifier: "BookDetailView") as? BookDetailViewController
        let item = items[indexPath.row]
        
        bookDetailVc?.bookItem = item
        bookDetailVc?.bookIndex = indexPath.row // 新增:传递索引
        
        self.navigationController?.pushViewController(bookDetailVc!, animated: true)
    }

    // 原有代码保持不变...
}

3. 修改BookDetailViewController实现

注意:BookDetailViewController无需继承HomeViewController,直接继承UIViewController即可,避免不必要的属性继承。新增属性接收书籍数据和索引,添加按钮点击事件发送通知:

class BookDetailViewController: UIViewController{ // 修改继承类为UIViewController

    @IBOutlet weak var bookTitle: UILabel!
    @IBOutlet weak var currentPageDetail: UILabel!
    @IBOutlet weak var totalPagesDetail: UILabel!
    @IBOutlet weak var updatePageButton: UIButton! // 假设你有一个更新页码的按钮
    
    var bookItem: BookItem? // 直接接收书籍对象
    var bookIndex: Int = 0 // 接收书籍在数据源中的索引

    override func viewDidLoad() {
        super.viewDidLoad()

        // 用bookItem初始化页面UI
        bookTitle.text = bookItem?.title
        currentPageDetail.text = bookItem?.currentPage
        totalPagesDetail.text = bookItem?.totalPages
    }
    
    // 更新页码按钮点击事件
    @IBAction func updatePageTapped(_ sender: UIButton) {
        // 示例:这里替换为你获取新页码的逻辑(比如输入框、步进器的值)
        let newCurrentPage = "100"
        
        // 更新当前页面显示
        currentPageDetail.text = newCurrentPage
        
        // 发送通知给HomeViewController更新表格
        NotificationCenter.default.post(
            name: .updateBookProgress,
            object: nil,
            userInfo: [
                "index": bookIndex,
                "currentPage": newCurrentPage
            ]
        )
    }
}

额外优化建议

  • 相比Notification Center,**闭包(Closure)或代理(Delegate)**类型更安全,能避免通知名称拼写错误、用户信息类型不匹配的问题,是更推荐的组件间通信方式。
  • 避免不必要的继承关系,BookDetailViewController只需要负责书籍详情展示和进度修改,无需继承HomeViewController。

内容的提问来源于stack exchange,提问作者alias.marv

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 11:30:50