Tommy K
Tommy K

Reputation: 1807

How to get data from the embedded controller in a container view

I have a general view controller with a button attached to the bottom and a container view above it. There is a table view embedded in the container view, that supports multiple selection. When 1 or more things have been selected in the tableview, I want the button to appear (slide up from bottom) and take the data selected in the tableview and use it to fire off a request from the general view controller. But my question is how do I get the data from that table view controller?

General
View Controller   
|         |
|         |
|container|-----> table view controller
|         |
|         |
|         |
|_________|
|   btn   |

that's a rough sketch of what I have going on. I'm using the container view so I can add the button and other UI elements freely to the overall view. If I have an array/list of things selected in the table view controller, how do I send it back to the General View Controller? Do I have to have the array/list in the General View Controller and some kind of a delegate in Table View Controller that takes the selected item and adds it into GVC?

Upvotes: 0

Views: 838

Answers (2)

John Dough
John Dough

Reputation: 285

In addition to using the delegate pattern, Swift makes it easy to use closure callbacks for single callback use cases where a protocol may feel like a bit of overhead:

class SelectionViewController: UIViewController {
    var itemsSelected: (([Item]) -> Void)!

    ...
    tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        itemsSelected(itemsForSelectedRows)
    }

    ...

    private var itemsForSelectedRows: [Item] {
         // Return the list of selected items based on e.g. tableView.indexPathsForSelectedRows
    }
}


class GeneralViewController: UIViewController {
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let controller = segue.destination as? SelectionViewController {
             // Note [weak self] to prevent a reference cycle between the two controllers
             controller.itemSelected = { [weak self] items in
                 self?.fireOffRequestSomewhere(items)
             }
        }
    }
}

Upvotes: 0

macabeus
macabeus

Reputation: 4592

Use the delegation pattern.

In your ViewController.swift:

protocol MyTableDelegate {
    func rowSelected()
}

class ViewController: UIViewController, MyTableDelegate {

    @IBOutlet weak var container: UITableViewController!
    var container: MyTable?

    ...

    func rowSelected() {
        // show my amazing button
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if segue.identifier == "myAmazingTable" {
            self.container = (segue.destination as! MyTable)
            self.container!.delegate = self
        }
    }

In your Table.swift:

class MyTable: UITableViewController {
    var delegate: MyTableDelegate?

    func rowWasSelected() {
        delegate!.rowSelected()
    }
}

Upvotes: 1

Related Questions