UITableView возвращает nil при вызове метода reloadData

Информационный проект:

У меня есть три представления: «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 есть собственный выход UITableView? Он расширяется UITableViewController. Это уже обеспечивает полностью настроенное табличное представление. Используй это.

rmaddy 22.07.2019 03:31

Также обратите внимание, что код, похожий на TaskTableVC().taskTable.refreshData(), — это не то, что вам нужно. Это создает совершенно новый экземпляр TaskTableVC. Вероятно, вы хотите получить доступ к какому-то существующему экземпляру контроллера представления.

rmaddy 22.07.2019 03:32

Это основа моего вопроса, как мне получить доступ к существующему экземпляру TaskTableVC

koza 22.07.2019 03:39
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
247
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть несколько вариантов, например, вы можете использовать Шаблон делегата для связи между этими 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 22.07.2019 18:47

Оно работает! Большое спасибо! Однако я все еще получаю ошибки выше? Но это все еще позволяет мне успешно строить, как ни странно.

koza 22.07.2019 20:44

@koza какую версию Swift вы используете? Это просто более чистый и простой синтаксис блока завершения. [weak self] чтобы избежать сохранения цикла. medium.com/@vinodhswamy/…

matuslittva 23.07.2019 20:11

Другие вопросы по теме