Swift 3.1 UITableViewController as subview or popup

Viewed 395

I have a tricky task. I have TableUIViewController (parent UIViewController) with two tableViews, buttons and so on. This UIViewController shows information about table in cafe.

I also have another controller with name MenuTableViewController (parent is UITableViewController), separate view that displays list of menu items. There are only three UI items - two labels and button in each cell.

Idea: I want to use this MenuTableViewController in two different ways.

  1. If segue to this view was performed from Main Menu - just show menu and allow user to edit each cell. Button.title = "Open".

  2. If view was opened from TableUIViewController - change button title to "Choose" and return to MenuTableViewController if button was pressed to create order and so on.

I have found that perform segue + prepare for segue works for me, but if I use segue, I'm getting an issue with Navigation Controller - I'm losing "back" button at all and cannot return to main menu.

So I think that I can use AddSubView or some popup do these steps:

  1. Click button in TableUIViewController

  2. Show MenuTableViewController

  3. Click on some button

  4. RETURN to TableUIViewController - ideally without any re-initialization, to keep all variables with their values.

But I cannot understand how to work with AddSubview here. Can somebody please guide me a bit? Or provide some example. Didn't find anything good here.

Here are my classes:

TableUIViewController

import UIKit
import CoreData

class TableUIViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, GuestAtTableTableViewCellDelegate, OrderInTableTableViewCellDelegate {
    //MARK: variables:
    //The following three variables will be set before segue to this view.
    fileprivate let myGenericFunctions = MyGenericFunctions()
    var tableName: String? = nil
    var currentTable: TablesTable? = nil
    var currentTableSession: TableSessionTable? = nil
    let tableSessionTable = TableSessionTable()
    let guestsTable = GuestsTable()
    fileprivate var countOfGuests: Int {
        get {
            guard currentTableSession != nil else {return 0}
            return guestsTable.getActiveGuestsForTable(tableSession: currentTableSession!)!.count
        }
    }
    fileprivate var guestsTableFetchedResultsController: NSFetchedResultsController<GuestsTable>?
    fileprivate var ordersTableFetchedResultsController: NSFetchedResultsController<OrdersTable>?


    //MARK: IBOutlets
    @IBOutlet weak var tableCapacityLabel: UILabel!
    @IBOutlet weak var tableCountOfGuestsLabel: UILabel!
    @IBOutlet weak var tableOpenTimeLabel: UILabel!
    @IBOutlet weak var tableDescriptionTextView: UITextView!
    @IBAction func closeTableButtonPressed(_ sender: UIButton) {
        guard currentTableSession != nil else {return}
        guestsTable.removeAllGuestsForTable(tableSession: currentTableSession!)
        updateGuestsTableView()
        updateOrdersTableView()
        tableSessionTable.removeTableSession(tableSession: currentTableSession!)
        currentTableSession = nil
        updateLabels()
    }
    @IBOutlet weak var guestsTableView: UITableView!
    @IBOutlet weak var ordersTableView: UITableView!

    @IBAction func addGuestButtonPressed(_ sender: UIButton) {
        if currentTableSession == nil {
            currentTableSession = tableSessionTable.createTableSession(table: currentTable!)
        }
        if let capacity = Int(tableCapacityLabel.text!) {
            guard capacity > countOfGuests else {return}
        }

        let guestsTable = GuestsTable()
        guestsTable.addNewGuest(tableSession: currentTableSession!)
        updateGuestsTableView()
        updateLabels()
    }
    @IBAction func addOrderButtonPressed(_ sender: UIButton) {
        guard currentTableSession != nil else {return}



    }


    //MARK: functions:
    override func viewDidLoad() {
        super.viewDidLoad()
        guestsTableView.dataSource = self
        guestsTableView.delegate = self
        ordersTableView.dataSource = self
        ordersTableView.delegate = self

        updateGuestsTableView()
        updateLabels()
    }


    private func updateLabels() {
        tableCapacityLabel.text = String(describing: currentTable!.tableCapacity)
        tableCountOfGuestsLabel.text = String(describing: countOfGuests)
        if currentTableSession != nil {
            tableOpenTimeLabel.text = String(describing: myGenericFunctions.convertDate(inputDate: currentTableSession!.openTime!))
        } else {
            tableOpenTimeLabel.text = " - "
        }
        if currentTable!.tableDescription != nil {
            tableDescriptionTextView.text = currentTable!.tableDescription
        }
    }

    //MARK: Delegates of cell buttons
    func didPressGuestCellButton(guest: GuestsTable) {
        guestsTable.closeGuest(guest: guest)
        updateLabels()
        updateGuestsTableView()
    }

    func didPressOrderCellButton(order: OrdersTable) {

    }

    //MARK: Functions for tableViews update
    private func updateGuestsTableView () {
        guard currentTableSession != nil else {return}
        let tableView = guestsTableView
        let context = AppDelegate.viewContext
        let request : NSFetchRequest<GuestsTable> = GuestsTable.fetchRequest()
        request.predicate = NSPredicate(format: "table= %@", currentTableSession!)
        request.sortDescriptors = [NSSortDescriptor(key: "openTime", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))]
        guestsTableFetchedResultsController = NSFetchedResultsController<GuestsTable>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        try? guestsTableFetchedResultsController?.performFetch()
        tableView?.reloadData()
    }

    private func updateOrdersTableView () {
        let tableView = ordersTableView
        let context = AppDelegate.viewContext
        let request : NSFetchRequest<OrdersTable> = OrdersTable.fetchRequest()
        request.sortDescriptors = [NSSortDescriptor(key: "menuItem", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))]
        ordersTableFetchedResultsController = NSFetchedResultsController<OrdersTable>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        try? ordersTableFetchedResultsController?.performFetch()
        tableView?.reloadData()
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if tableView == self.guestsTableView {
            let cell = tableView.dequeueReusableCell(withIdentifier: "guestCell", for: indexPath) as! GuestAtTableTableViewCell
            if let guest = guestsTableFetchedResultsController?.object(at: indexPath) {
                cell.guestNameLabel.text = guest.guestName
                cell.openTimeLabel.text = "Пришел: " + myGenericFunctions.convertDate(inputDate: guest.openTime!)
                if let closeTime = guest.closeTime {
                    cell.closeTimeLabel.text = "Ушел: " + myGenericFunctions.convertDate(inputDate: closeTime)
                    cell.closeGuestButton.isEnabled = false
                    cell.guestNameLabel.textColor = UIColor.darkGray
                    cell.openTimeLabel.textColor = UIColor.darkGray
                    cell.closeTimeLabel.textColor = UIColor.darkGray
                }
                cell.cellDelegate = self
                cell.guest = guest
            }
            return cell
        }
        else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "orderCell", for: indexPath)
            return cell
        }
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        if tableView == self.guestsTableView {
            return guestsTableFetchedResultsController?.sections?.count ?? 1
        }
        else if tableView == self.ordersTableView {
            return ordersTableFetchedResultsController?.sections?.count ?? 1
        }
        else {return 1}
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if tableView == self.guestsTableView {
            if let sections = guestsTableFetchedResultsController?.sections, sections.count > 0 {
                return sections[section].numberOfObjects
            }
            else {
                return 0
            }
        }
        else if tableView == self.ordersTableView {
            if let sections = ordersTableFetchedResultsController?.sections, sections.count > 0 {
                return sections[section].numberOfObjects
            }
            else {
                return 0
            }
        }
        else {return 0}
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if tableView == self.guestsTableView {
            if let sections = guestsTableFetchedResultsController?.sections, sections.count > 0 {
                return sections[section].name
            }
            else {
                return nil
            }
        }
        else if tableView == self.ordersTableView {
            if let sections = ordersTableFetchedResultsController?.sections, sections.count > 0 {
                return sections[section].name
            }
            else {
                return nil
            }
        }
        else {return nil}

    }

    func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        if tableView == guestsTableView {
            return guestsTableFetchedResultsController?.sectionIndexTitles
        }
        else {
            return ordersTableFetchedResultsController?.sectionIndexTitles
        }
    }

    func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
        if tableView == guestsTableView {
            return guestsTableFetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
        }
        else if tableView == ordersTableView {
            return ordersTableFetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
        }
        else {return 0}
    }

    //Prepare for segues
    /*override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "openMenuToAddOrder" {
            if let menuTVC = segue.destination as? MenuTableViewController {
                menuTVC.isOpenedFromTable = true
                menuTVC.currentTableSession = currentTableSession
                menuTVC.currentTable = currentTable
            }
        }
    }*/
}

ManuTableViewController:

class MenuTableViewController: FetchedResultsTableViewController, MenuTableViewCellDelegate {
    var tableName: String? = nil
    var currentTable: TablesTable? = nil
    var currentTableSession: TableSessionTable? = nil
    var isOpenedFromTable: Bool = false
    let ordersTable = OrdersTable()
    fileprivate var fetchedResultsController: NSFetchedResultsController<MenuTable>?

    override func viewDidLoad() {
        updateMenuTableView()
        self.navigationItem.rightBarButtonItem = self.editButtonItem
    }

    //MARK: delegate of table cell
    func didPressMenuItemCellButton (menuItem: MenuTable) {
        if isOpenedFromTable {
            ordersTable.addOrUpdateOrderForTableSession(tableSession: currentTableSession!, menuItem: menuItem)
            performSegue(withIdentifier: "returnToTableView", sender: self)
        } else {
            //here will be code for editing menu item
        }
    }

    //MARK: Functioms for table view update
    private func updateMenuTableView () {
        let context = AppDelegate.viewContext
        let request : NSFetchRequest<MenuTable> = MenuTable.fetchRequest()
        request.sortDescriptors = [NSSortDescriptor(key: "itemName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))]
        fetchedResultsController = NSFetchedResultsController<MenuTable>(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        fetchedResultsController?.delegate = self
        try? fetchedResultsController?.performFetch()
        tableView.reloadData()
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "menuCell", for: indexPath) as! MenuTableViewCell
        if let menuTable = fetchedResultsController?.object(at: indexPath) {
            cell.menuItemNameLabel.text = menuTable.itemName
            cell.menuItemDescriptionLabel.text = menuTable.itemDescription
            cell.menuItemPriceLabel.text = String(describing: menuTable.itemPrice)
            if isOpenedFromTable == true {
                cell.button.setTitle("Выбрать", for: UIControlState.normal)
            } else {
                cell.button.setTitle("Открыть", for: UIControlState.normal)
            }
            cell.menuItem = menuTable
            cell.cellDelegate = self
        }
        return cell
    }
    //Prepare for segues
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "returnToTableView" {
            if let tableTVC = segue.destination as? TableUIViewController {
                tableTVC.currentTableSession = currentTableSession
                tableTVC.currentTable = currentTable
                tableTVC.tableName = currentTable?.tableName
            }
        }
    }
}

extension MenuTableViewController {
    override func numberOfSections(in tableView: UITableView) -> Int {
        return fetchedResultsController?.sections?.count ?? 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let sections = fetchedResultsController?.sections, sections.count > 0 {
            return sections[section].numberOfObjects
        }
        else {
            return 0
        }
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        if let sections = fetchedResultsController?.sections, sections.count > 0 {
            return sections[section].name
        }
        else {
            return nil
        }
    }

    override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        return fetchedResultsController?.sectionIndexTitles
    }

    override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
        return fetchedResultsController?.section(forSectionIndexTitle: title, at: index) ?? 0
    }
}

UPDATE: Here is my storyboard. I have a feeling that I'm using Navigation controller not properly. But without some controller between views - back button does not appear. And sorry for russian text in the image. enter image description here

UPDATE after marked as resolved:

I have removed performSegue and put segues from Controller to button itself. Now Navigation controller keeps Back button as it should. Also moves Update UI functions to viewWillAppear to keep tables updated after segues.

override func viewWillAppear(_ animated: Bool) {
    updateGuestsTableView()
    updateOrdersTableView()
    updateLabels()
    updateOrdersTableView()
}

Another update, now it works absolutely as I wanted. I have added to function that is called by Menu Cell Button to return to previous ViewController (same as Back button does):

    //MARK: delegate of table cell
    func didPressMenuItemCellButton (menuItem: MenuTable) {
        if isOpenedFromTable {
            ordersTable.addOrUpdateOrderForTableSession(tableSession: currentTableSession!, 

menuItem: menuItem)
            _ = navigationController?.popViewController(animated: true)
        } else {
            //here will be code for editing menu item
        }
    }
1 Answers
Related