almiteyG almiteyG - 2 months ago 14x
iOS Question

Swift - Using UITableViewController to create sub-menus

I am developing a simple hybrid iOS app using Xcode 7 and Swift 2. I need to create submenus from my main menu.

My main menu uses a table view. Now I can create a second

and load the sub menu within that and create a third
to load another sub menu and so on.

But is there a better way by reusing my initial

is embedded in a

And I am using a single
to show the final textual information.

enter image description here

Here is my Main Menu code:

class MainMenuTableViewController: UITableViewController {

// MARK: Properties

var mainMenu = [MainMenu]()
var Item1Menu = [MainMenu]()
var Item12Menu = [MainMenu]()
var selectedMenu: Int = 0

override func viewDidLoad() {

// Load the sample data.


func loadMainMenu() {
let image1 = UIImage(named: "menu-1")!
let menuItem1 = MainMenu(name: "Item 1", photo: image1, url: "no-url", urlType: "subMenu")!

let image2 = UIImage(named: "menu-2")!
let menuItem2 = MainMenu(name: "Item 2", photo: image2, url: "our-services", urlType: "localURL")!

let image3 = UIImage(named: "menu-3")!
let menuItem3 = MainMenu(name: "Item 3", photo: image3, url: "", urlType: "webURL")!

let image4 = UIImage(named: "menu-1")!
let menuItem4 = MainMenu(name: "Item 4", photo: image4, url: "our-info", urlType: "localURL")!

let image5 = UIImage(named: "menu-2")!
let menuItem5 = MainMenu(name: "Item 5", photo: image5, url: "", urlType: "webURL")!

mainMenu += [menuItem1, menuItem2, menuItem3, menuItem4, menuItem5]

func loadItem1Menu() {
let image = UIImage(named: "menu-1")!
let menuItem1 = MainMenu(name: "Item 1.1", photo: image, url: "our-profile", urlType: "localURL")!

let menuItem2 = MainMenu(name: "Item 1.2", photo: image, url: "no-url", urlType: "sub-menu")!

let menuItem3 = MainMenu(name: "Item 1.3", photo: image, url: "our-history", urlType: "localURL")!

Item1Menu += [menuItem1, menuItem2, menuItem3]

func loadItem12Menu() {
let image = UIImage(named: "menu-1")!
let menuItem1 = MainMenu(name: "Item 1.2.1", photo: image, url: "portfolio-1", urlType: "localURL")!

let menuItem2 = MainMenu(name: "Item 1.2.2", photo: image, url: "portfolio-2", urlType: "localURL")!

let menuItem3 = MainMenu(name: "Item 1.2.3", photo: image, url: "portfolio-3", urlType: "localURL")!

Item12Menu += [menuItem1, menuItem2, menuItem3]

override func didReceiveMemoryWarning() {
// Dispose of any resources that can be recreated.

// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mainMenu.count

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "MainMenuTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! MainMenuTableViewCell

// Fetches the appropriate menu for the data source layout.
let menu = mainMenu[indexPath.row]

cell.nameLabel.text =
cell.menuImageView.image =

return cell

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

var segueString:String
selectedMenu = indexPath.row
let urlType = mainMenu[selectedMenu].urlType

if urlType == "subMenu" {

let vc = (UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())).instantiateViewControllerWithIdentifier("MenuViewController") as! MainMenuTableViewController

vc.mainMenu = Item1Menu
// then push or present view controller
self.navigationController!.pushViewController(vc, animated: true)

} else {


case "localURL":
segueString = "ShowLocalWeb"
segueString = "ShowWeb"

self.performSegueWithIdentifier(segueString, sender: self)

// MARK: - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

if segue.identifier == "ShowSubMenu" {
let subMenuController = segue.destinationViewController as! SubMenuTableViewController
subMenuController.subMenu = mainMenu[selectedMenu]

if segue.identifier == "ShowLocalWeb" {
let localViewController = segue.destinationViewController as! LocalWebViewController
localViewController.mainMenu = mainMenu[selectedMenu]

if segue.identifier == "ShowWeb" {
let webViewController = segue.destinationViewController as! WebViewController
webViewController.mainMenu = mainMenu[selectedMenu]




Actually you are all set to go. The only change you need is create an instance of MainMenuTableViewController and assign mainMenu with your new menu.


When you wish to show new menu.

let vc = MainMenuTableViewController() = <new menu here>
// then push or present view controller
self.navigationController.pushViewController(vc, animated: true)

Response to Comment below:

No, you dont have to create new file, but new instance of MainMenuTableViewController. You have to change the data part, in your case array that contains menu. <new menu here> refers to array of new menu items.

For this you have to Decouple the data, which will be helpful.


Instead of creating your vc in the above fashion you can try creating it from the storyboard. Please follow the steps:

  1. In storyboard assign storyboard identifier to MainMenuTableViewController and instead of this line

let vc = MainMenuTableViewController()


let vc = (UIStoryboard(name: <your storyboard file name>, bundle: NSBundle.mainBundle())).instantiateViewControllerWithIdentifier(<storyboard identifier of MainMainMenuTableViewController>)

The reason I suspect is the line that i previously is unable find cell to create and hence crasing.