Reputation: 1411
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.
If segue to this view was performed from Main Menu - just show menu and allow user to edit each cell. Button.title = "Open".
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:
Click button in TableUIViewController
Show MenuTableViewController
Click on some button
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.
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
Reputation: 77486
It sounds like you want a structure something like this:
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