DJ-Glock
DJ-Glock

Reputation: 1411

Swift 3.1 UITableViewController as subview or popup

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

Upvotes: 2

Views: 415

Answers (1)

DonMag
DonMag

Reputation: 77486

It sounds like you want a structure something like this:

enter image description here

If you select "Edit Food Menu" from the Main Menu, you will be taken directly to the "Food Menu". If you select "Take Orders" you will see the "List of Tables".

If you selected "Edit Food Menu" then your Food Menu code should display "Edit" as the button title for each row in the table. Tapping "Edit" would then take you to the "Edit Menu Item" view.

If you selected "Take Orders" and then select a table from the List, that will also take you to the "Food Menu", but in that case your Food Menu code should display "Order" as the button titles. Tapping "Order" would add that food item to your data structure, or maybe show a confirmation alert, or do whatever else is needed at that point.

Because all of the views are part of the same Navigation Controller structure, you will always be able to "walk back up the stack" by selecting the standard "< Back" button on the navigation bar.

Hope that makes some sense :)

Upvotes: 2

Related Questions