Информационный проект:
У меня есть три представления: «Main, AddTask и TaskTable» и три контроллера представлений: «MainVC, AddTaskVC, TaskTableVC». В моем «Основном» представлении есть встроенный «UITableView», который является «TaskTable». В моем «Основном» представлении также есть кнопка, представляющая модальное представление «Добавить задачу». В моем представлении «Добавить задачу» есть кнопка, которая закрывается. Мой «TaskTableVC» имеет объект с именем «taskTable», который является «UITableView».
Цель:
Я пытался вызвать reloadData
на taskTable
, когда модальное представление AddTask
закрыто. Однако, независимо от того, как я справлюсь с этим, я не могу вызвать reloadData
на taskTable
, потому что он всегда кажется нулевым после того, как AddTask
появляется в первый раз.
Исследование проблемы:
Первое, что я сделал, это напрямую вызвал reloadData()
на моем taskTable
объекте, используя completion
, когда AddTask
был отклонен:
self.dismiss(animated: true, completion: {
TaskTableVC().taskTable.refreshData()
})
но я быстро понял, что не могу вызвать его напрямую, потому что представление TaskTable
не было загружено, а я создавал экземпляр.
Затем я помещаю заявления печати в свой viewDidLoad
для трех представлений (см. Информацию о проекте). При запуске первым загружается мой TaskTable
, а затем мой Main
. Когда я нажимаю кнопку на моем Main
моем AddTask
загружается. Пока все хорошо... Однако, когда я закрываю AddTask
, ничего не загружается. Я думал, что мои TaskTable
и Main
загрузятся, но этого не произошло. Поэтому я попытался вызвать функцию refreshData()
, которая была частью MainVC
на completion
из dismiss
в AddTaskVC
. Функция загружала представление 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
Мне нужно вызвать reloadData
во встроенном UITableView
, когда я вызываю отклонение в модальном представлении.
//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
}
//...
}
Также обратите внимание, что код, похожий на TaskTableVC().taskTable.refreshData()
, — это не то, что вам нужно. Это создает совершенно новый экземпляр TaskTableVC
. Вероятно, вы хотите получить доступ к какому-то существующему экземпляру контроллера представления.
Это основа моего вопроса, как мне получить доступ к существующему экземпляру TaskTableVC
Есть несколько вариантов, например, вы можете использовать Шаблон делегата для связи между этими ViewControllers, есть также некоторые другие варианты, такие как Шаблон наблюдателя или RxSwift, вы также можете оставить некоторую ссылку непосредственно на эти встроенные ViewControllers, но я не рекомендую это делать.
Поскольку между этими встроенными ViewController'ами существуют переходные отношения, мы можем использовать метод 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()
}
}
swift dismiss(animated: true) { [weak self] in self?.delegate?.tasksChanged() }
тоже опечатка? Куда пропало завершение и что такое [weak self] in
?
Оно работает! Большое спасибо! Однако я все еще получаю ошибки выше? Но это все еще позволяет мне успешно строить, как ни странно.
@koza какую версию Swift вы используете? Это просто более чистый и простой синтаксис блока завершения. [weak self]
чтобы избежать сохранения цикла. medium.com/@vinodhswamy/…
Почему у вашего
TaskTableVC
есть собственный выход UITableView? Он расширяетсяUITableViewController
. Это уже обеспечивает полностью настроенное табличное представление. Используй это.