0

I have a TableView that displays a list of entries in the cells. The entries are stored in an array. The user enters in text for the entries in another view controller (modal), hits "Save", and after .reloadData(), the new entry should append to the array and display in the TableView. The array lives in the HomeController.

To pinpoint where the problem might be, I've tried appending some text in the HomeController, then appending to the same array from the NotesController. In the latter, when I print homeController.entryInput, I'm expecting ["hello", "goodbye"]. Instead, I only get ["goodbye"].

Also, when I click on "Save" in NotesController a second time, I get ["goodbye"] again instead of ["goodbye", "goodbye"]. So it looks like the array gets overrided.

I've also tried hard coding items into the array, and they show up fine in the TableView. When I append an item from NotesController, it appends to the array but doesn't show on the TableView, and when I add another item from the same ViewController, it overwrites the first item I appended rather than adding it as a new item.

HomeController:

class HomeController: UIViewController {

    let tableView = UITableView()

    var entryInput: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        setupTableView()
    }

    func setupTableView() {
        tableView.delegate = self
        tableView.dataSource = self

        self.entryInput.append("hello")
        print(entryInput)

        tableView.register(HomeCell.self, forCellReuseIdentifier: reuseIdentifier)

        let height = view.frame.height
        tableView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: height)

        tableView.backgroundColor = .white

        view.addSubview(tableView)
    }

extension HomeController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return entryInput.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = self.tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! HomeCell
        cell.entryTextLabel.text = entryInput[indexPath.row]

        return cell
    }

NotesController:

class NotesController: UIViewController {
    let homeController = HomeController()
    ...
    let saveBtn = UIView().navigationBtn(text: "Save")

    let homeController = HomeController()override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white

        saveBtn.addTarget(self, action: #selector(save(sender:)), for: .touchUpInside)
    }

    @objc func save(sender: UIButton) {
        homeController.entryInput.append("goodbye")
        homeController.tableView.reloadData()

        print(homeController.entryInput)

        dismiss(animated: true, completion: nil)
    }
}

I've looked all around Stack Overflow and other websites about appending to arrays but for some reason can't seem to figure out why I can't append to an array in another class.

  • Add log in viewDidLoad of HomeController class and check if it is getting called or not. – Parag Bafna May 03 '20 at 06:47
  • It could be that you have multiple HomeViewController. So when you are appending data to the HomeViewController from NotesController it is a new instance. Is the NotesController the main VC or the modal you're talking about? – grandouassou May 03 '20 at 07:09

2 Answers2

0

It looks like the line:

let homeController = HomeController()

creates a new instance of the class HomeController and does not refer to the already existing ViewController. Which means: modifying the array in the new instance of HomeController won't affect your main ViewController.

This also leads to the answer of your question about the missing "hello"-element in your array. When you create the object homeController it's array does not have any elements.

When @objc func save(sender: UIButton) get's called, you append "goodbye" to the empty array.

By calling dismiss(...) you are returning to the original version of your HomeController() which does not know anything about the other instance you created in NotesController().

To achieve what you are trying to do, I recommend reading more about how to pass data between ViewControllers:

Adrian
  • 352
  • 1
  • 11
0

Because you have create new HomeController in NotesController that doesn't reference to your current HomeController.

class NotesController: UIViewController {
    let homeController = HomeController()
}

When HomeController want to open NotesController. And NotesController want to communicate back to HomeController. You should pass HomeController reference to NotesController.

func routeToNotesController() {
    let vc = NotesViewController()
    vc.homeController = self
    let nc = UINavigationController(rootViewController: vc)
    present(nc, animated: true)
}

Answer your questions.

  1. From the NotesController after save called. You're expecting ["hello","goodbye"] but you get ["goodbye"] instead.

    • Because you are instantiate HomeController in NotesViewController The homeController that you create is not the same HomeController appear on the screen, It's new so homeController and entryInput still empty because viewDidLoad isn't call.
  2. When you add another item from NotesViewController, You're expecting ["goodbye", "goodbye"] but you get ["goodbye"] instead.

    • According the first answer. You create new homeController(that not relate to existing one on the screen) inside NotesController every time it appear on the screen.

Here is the result.

  • Left image show HomeController.
  • Middle image show HomeController that open InputsController.
  • Right image show HomeController that updated by InputsController.


My implementation.

class ListViewController: UITableViewController {
    var entryInput: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.title = "ListViewController"
        tableView.backgroundColor = .white
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(add))
        entryInput.append("hello")
        tableView.reloadData()
    }

    @objc func add() {
        let vc = InputViewController()
        vc.listViewController = self
        let nc = UINavigationController(rootViewController: vc)
        present(nc, animated: true)
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return entryInput.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = entryInput[indexPath.row]
        return cell
    }
}

class InputViewController: UIViewController {
    weak var listViewController: ListViewController?

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.title = "InputViewController"
        view.backgroundColor = .white
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(save))
    }

    @objc func save() {
        listViewController?.entryInput.append("goodbye")
        listViewController?.tableView.reloadData()
        dismiss(animated: true)
    }
}
ssankosik
  • 88
  • 5
  • 1
    Thanks a lot for your example and detailed answer. I understand why **vc**, although I wasn't clear enough in my statement that by the time **NotesController** appears, it's already been pushed onto a stack of views. When user taps "Add", the first one in the stack is presented modally and embedded in a NavController, user clicks through the VCs until the last one, **NotesController** which is dismissed when user taps "Save". What can I do instead? – Stephanie Chiu May 04 '20 at 07:18