Search code examples
arraysswiftuitableviewviewcontroller

Item appends to array in one view controller but not in another


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.


Solution

  • 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)
        }
    }