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

Swift中代理方法无法更新UITableView数据的问题排查

问题原因

你现在的核心问题是**TopicViewController和ViewController各自创建了独立的Engine实例**——也就是说两个控制器用的不是同一个Engine对象。当你调用addCourse或addTopic时,触发delegate?.didAddCourse()的是其中一个Engine实例(比如ViewController里的那个),但TopicViewController绑定的是另一个完全独立的Engine,所以它的didAddCourse方法根本不会被调用,表格自然不会更新。

解决方案

方案1:把Engine改成单例(全局唯一实例)

这样所有控制器都共用同一个Engine,代理绑定后就能收到回调。

修改EngineController.swift:

protocol EngineDelegate: AnyObject {
    func didAddCourse()
}

class Engine {
    // 单例实现,全局唯一实例
    static let shared = Engine()
    // 私有化构造方法,防止外部随便创建新实例
    private init() {}
    
    weak var delegate: EngineDelegate?
    // 补充你原来的属性(courses数组、索引变量等)
    var courses: [Course] = []
    var requestedCourseIndex: Int = 0
    var requestedTopicIndex: Int = 0
    
    func addCourse(name: String, content: String) {
        let separatedContent = content.components(separatedBy: "\n")
        
        courses.append(Course(name: name, description: "" ,topics: []))
        for topic in separatedContent {
            courses[courses.endIndex - 1].topics.append(Course.Topic(subTopics: [], topicName: topic))
        }
        delegate?.didAddCourse()
    }
    
    func addTopic(content: String) {
        let separatedContent = content.components(separatedBy: "\n")
        
        for topic in separatedContent {
            courses[requestedCourseIndex].topics[requestedTopicIndex].subTopics.append(Course.Topic.SubTopic(subTopicName: topic, subTopicBody: ""))
        }
        let topics = courses[requestedCourseIndex].topics[requestedTopicIndex].subTopics.count
        print(topics)
        delegate?.didAddCourse()
    }
}

然后修改两个控制器的engine实例,改成用单例:
TopicViewController.swift:

import UIKit

class TopicViewController: UITableViewController, EngineDelegate {
    
    // 不再自己创建,用全局单例
    let engine = Engine.shared
    
    func didAddCourse() {
        DispatchQueue.main.async {
            self.tableView.reloadData()
            self.stopCellAnimation()
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // 绑定代理
        engine.delegate = self
    }
    
    // 确保你的tableView数据源方法用的是engine.courses,比如:
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return engine.courses.count
    }
}

ViewController.swift同理:

import UIKit

class ViewController: UITableViewController, EngineDelegate {
    
    let engine = Engine.shared

    override func viewDidLoad() {
        super.viewDidLoad()
        engine.delegate = self
    }
    
    func didAddCourse() {
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
    
    // 数据源方法同样使用engine.courses
}

⚠️ 注意:如果两个控制器同时设置engine.delegate = self,最后设置的会覆盖之前的,因为delegate是单个弱引用对象。如果需要两个控制器都收到回调,用下面的多代理方案。

方案2:支持多代理(让多个控制器同时收到回调)

修改EngineController.swift的代理部分,用数组存储多个代理:

protocol EngineDelegate: AnyObject {
    func didAddCourse()
}

class Engine {
    static let shared = Engine()
    private init() {}
    
    // 用数组存储多个代理,弱引用避免循环引用
    private var delegates: [WeakDelegate] = []
    
    // 添加代理的方法
    func addDelegate(_ delegate: EngineDelegate) {
        // 避免重复添加同一个代理
        if !delegates.contains(where: { $0.delegate === delegate }) {
            delegates.append(WeakDelegate(delegate: delegate))
        }
    }
    
    // 移除代理的方法(比如控制器销毁时调用)
    func removeDelegate(_ delegate: EngineDelegate) {
        delegates.removeAll(where: { $0.delegate === delegate })
    }
    
    // 遍历所有代理,调用方法
    private func notifyDidAddCourse() {
        // 先过滤掉已释放的代理
        delegates = delegates.filter { $0.delegate != nil }
        delegates.forEach { $0.delegate?.didAddCourse() }
    }
    
    // 包装类,用来实现弱引用数组
    private class WeakDelegate {
        weak var delegate: EngineDelegate?
        init(delegate: EngineDelegate) {
            self.delegate = delegate
        }
    }
    
    // 原有方法不变,把delegate?.didAddCourse()换成notifyDidAddCourse()
    func addCourse(name: String, content: String) {
        // ...原有代码
        notifyDidAddCourse()
    }
    
    func addTopic(content: String) {
        // ...原有代码
        notifyDidAddCourse()
    }
    
    // 你的其他属性
    var courses: [Course] = []
    var requestedCourseIndex: Int = 0
    var requestedTopicIndex: Int = 0
}

然后在控制器里绑定代理:
TopicViewController.swift的viewDidLoad:

override func viewDidLoad() {
    super.viewDidLoad()
    engine.addDelegate(self)
}

// 别忘了在控制器销毁时移除代理,避免内存问题
deinit {
    engine.removeDelegate(self)
}

ViewController.swift同样修改即可,这样两个控制器都能收到didAddCourse的回调,各自刷新表格。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 05:02:10