UITableView 在调用 reloadData 方法时返回 nil

UITableView returning nil when reloadData method is called upon it

项目信息:

我有三个视图:'Main, AddTask, and TaskTable' 和三个视图控制器:'MainVC, AddTaskVC, TaskTableVC'。 我的 'Main' 视图有一个嵌入的 'UITableView',即 'TaskTable'。 我的 'Main' 视图也有一个按钮,它显示一个模态视图 'AddTask'。 我的 'AddTask' 视图有一个自动关闭的按钮。 我的 'TaskTableVC' 有一个名为 'taskTable' 的对象,它是 'UITableView'

目标:

当模式视图 AddTask 被关闭时,我一直在尝试在 taskTable 上调用 reloadData。但是,无论我如何解决这个问题,我都无法在 taskTable 上调用 reloadData,因为在 AddTask 第一次出现后它似乎总是 nil。

问题研究:

我做的第一件事是在 AddTask 被关闭时使用 completion 在我的 taskTable 对象上直接调用 reloadData()

self.dismiss(animated: true, completion: {           
    TaskTableVC().taskTable.refreshData()
})

但我很快了解到我不能直接调用它,因为 TaskTable 视图没有加载并且我正在创建一个实例。

接下来,我在我的 viewDidLoad 上打印了我的三个视图的语句(请参阅项目信息)。启动时,首先加载的是我的 TaskTable,然后是我的 Main。当我单击 Main 上的按钮时,我的 AddTask 加载。到目前为止一切顺利...但是,当我关闭 AddTask 时,没有加载任何内容。我以为我的 TaskTableMain 会被加载,但事实并非如此。所以我尝试在 AddTaskVC 中的 dismisscompletion 上调用属于 MainVC 的函数 refreshData() 该函数将加载 TaskTable 视图使用loadViewIfNeeded:

func refreshData() {
     TaskTableVC().loadViewIfNeeded()
}

然后在我的TaskTableVC下我的viewDidLoad我有:

override func viewDidLoad() {
    super.viewDidLoad()
    print("table view loaded")
    self.taskTable.reloadData()
}

然而我继续得到的错误是:Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value 我相信这是因为我通过实例调用了 TaskTableVC.loadViewIfNeeded()?不管是什么情况,我一辈子都无法让它发挥作用。

TL;DR 当我在模态视图上调用 dismiss 时,我需要在嵌入式 UITableView 上调用 reloadData

//MainVC:
class MainVC: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        print("main view loaded")
    }

    func refreshData() {
        TaskTableVC().loadViewIfNeeded()
    }
}
//AddTaskVC
class AddTaskVC: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        print("AddTask view loaded")
    }
    //...
    @IBAction func addTask(_ sender: Any) {
        //...
        self.dismiss(animated: true, completion: {     
            MainVC().refreshData()
        })
    }
}
//TaskTableVC
class TaskTableVC : UITableViewController {

    @IBOutlet var taskTable: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        print("table view loaded")
        self.taskTable.reloadData() //error here
    }
    //...
}

有几个选项,例如你可以使用Delegate pattern to communicate between those ViewControllers, there are also some other options like Observer pattern or RxSwift,你也可以直接保留一些对那些嵌入的ViewControllers的引用,但我不建议这样做。

由于这些嵌入式 ViewController 之间存在 segue 关系,我们可以使用 prepare(for segue 方法来评估这些委托。

class MainVC: UIViewController, TasksUpdateDelegate {

    weak var tasksTableDelegate: TaskTableDelegate?

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let taskTableVC = segue.destination as? TaskTableVC {
            tasksTableDelegate = taskTableVC
        } else if let addTaskVC = segue.destination as? AddTaskVC {
            addTaskVC.delegate = self
        }
    }

    func tasksChanged() {
        tasksTableDelegate?.reloadTasks()
    }

}

TasksUpdateDelegate 通知 MainVC 任务的任何变化。

protocol TasksUpdateDelegate: class {
    func tasksChanged()
}

class AddTaskVC: UIViewController {

    weak var delegate: TasksUpdateDelegate?

    @IBAction func addTask(_ sender: Any) {
        dismiss(animated: true) { [weak self] in
            self?.delegate?.tasksChanged()
        }
    }
}

TasksTableDelegate在MainVC中用于通知TaskTableVC应该重新加载tasksTable

protocol TaskTableDelegate: class {
    func reloadTasks()
}

class TaskTableVC: UITableViewController, TaskTableDelegate {

    @IBOutlet var taskTable: UITableView!

    func reloadTasks() {
        taskTable.reloadData()
    }

}