Building a restaurant iOS App
Published: 2021-12-29 11:36:34

---
title: Building a restaurant iOS App
published: true
description: 
tags: 
//cover_image: https://direct_url_to_image.jpg
---

We are building a simple food ordering iOS Application with Swift 5! It would look something like this after we build it:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bijjjdfafhdz7ony8srn.png)
  

Let's quickly go through a rough architecture of the application. We'll have two ViewControllers in our application:
 

- **RestaurantListingsViewController**
    
    This will be the home `viewController` of the app. This is where the user will land after opening the app. It will fetch the restaurants data from our backend and display it in a simple **`TableViewController`.** When the user will click on any one of them, we'll take him to the menu screen of the restaurant.
    
- **RestaurantMenuViewController**
After clicking on any one of the restaurants from our home scene, this `viewController` will fetch the menu items for it, let the user add them to his cart and place an order!

We'll be using [Alamofire](https://github.com/Alamofire/Alamofire) networking library to help us communicate with our Backend easily and help us focus on building the actual app.

### Step 1: Create & Setup a new Project

Open Xcode and click on **Create a new Xcode Project**.

- Select the **`App`** option
- Enter the name: **Restaurant App**
- We'll be using **`Swift`** as our **language** and **`Storyboard`** as our **Interface**
- Click **`Next`** and create your project!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqbm6pe654wnpmf71p6s.png)
 
To add [Alamofire](https://github.com/Alamofire/Alamofire), we'll be using [Swift Package Manager](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app). Xcode comes with built-in support for it and we'll not have to use external package managers like [Cocoapods](https://github.com/CocoaPods/CocoaPods) or [Carthage](https://github.com/Carthage/Carthage). Click on **File → Add Packages...**

Enter the following Package URLs in the search bar and add: Alamofire & AlamofireImage

```bash
https://github.com/Alamofire/AlamofireImage.git
https://github.com/Alamofire/Alamofire.git
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sq9tfc9xbbpfy3c1t6d0.png) 

Our project is set and ready to be built, let's dive in 🏃‍♂️

### Step 2: Setup Data Modals and Helpers

Before creating any of our views and controllers, we'll set up our data modals that will hold the data that will be used inside our `viewControllers`. We'll create three modal files:

- **Restaurant.swift**
    
    This will a `struct` confirming to `Codable` protocol that will hold the data for our restaurants. When we'll fetch all the restaurants, the data coming in from the backend will be decoded into this struct. 
    
    ```swift
    //
    //  Restaurant.swift
    //  Restaurant App
    //
    
    import Foundation
    
    struct Restaurants: Codable {
        let restaurants: [Restaurant]
        
        enum CodingKeys: String, CodingKey {
            case restaurants = "data"
        }
    }
    
    struct Restaurant: Codable {
        var id, name, description: String
        let brandImage: BrandImage?
        
        enum CodingKeys: String, CodingKey {
            case id = "_id"
            case name, description, brandImage
        }
        
        init() {
            
            id = ""
            name = ""
            description = ""
            brandImage = BrandImage()
        }
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            id = try container.decode(String.self, forKey: .id)
            name = try container.decode(String.self, forKey: .name)
            description = try container.decode(String.self, forKey: .description)
            brandImage = try container.decodeIfPresent(BrandImage.self, forKey: .brandImage)
        }
    }
    
    struct BrandImage: Codable {
        let url, alt, name: String?
        
        enum CodingKeys: String, CodingKey {
            case url, alt, name
        }
        
        init() {
            url = ""
            alt = ""
            name = ""
        }
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            url = try container.decodeIfPresent(String.self, forKey: .url)
            alt = try container.decodeIfPresent(String.self, forKey: .alt)
            name = try container.decodeIfPresent(String.self, forKey: .name)
        }
    }
    ```
    
- **Menu.swift**
    
    This will a `struct` confirming to `Codable` protocol that will hold the data for our menu items. When we'll fetch the menu items for any particular restaurant, the data coming in from the backend will be decoded into this struct.
    
    ```swift
    //
    //  Menu.swift
    //  Restaurant App
    //
    
    import Foundation
    
    struct Menus: Codable {
        let menus: [Menu]
        
        enum CodingKeys: String, CodingKey {
            case menus = "data"
        }
    }
    
    struct Menu: Codable {
        var id, itemName, description, price: String
        let itemImage: ItemImage?
        
        enum CodingKeys: String, CodingKey {
            case id = "_id"
            case itemName, description, itemImage, price
        }
        
        init() {
            itemName = ""
            description = ""
            price = ""
            id = ""
            itemImage = ItemImage()
        }
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            id = try container.decode(String.self, forKey: .id)
            itemName = try container.decode(String.self, forKey: .itemName)
            description = try container.decode(String.self, forKey: .description)
            itemImage = try container.decodeIfPresent(ItemImage.self, forKey: .itemImage)
            price = try container.decode(String.self, forKey: .price)
        }
    }
    
    struct ItemImage: Codable {
        let url, alt, name: String?
        
        enum CodingKeys: String, CodingKey {
            case url, alt, name
        }
        
        init() {
            url = ""
            alt = ""
            name = ""
        }
        
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            url = try container.decodeIfPresent(String.self, forKey: .url)
            alt = try container.decodeIfPresent(String.self, forKey: .alt)
            name = try container.decodeIfPresent(String.self, forKey: .name)
        }
    }
    ```
    
- **Order.swift**
    
    This will a `struct` confirming to `Codable` protocol that will hold the details of the order the user is placing. We'll send this data to our backend when the user places his confirmed order.
    
    ```swift
    //
    //  Order.swift
    //  Restaurant App
    
    import Foundation
    
    struct Order: Codable {
        var restaurant: String
        var totalAmount: String
        var orderItems: [OrderItems]
        
        init() {
            restaurant = ""
            totalAmount = ""
            orderItems = []
        }
    }
    
    struct OrderItems: Codable {
        var item: String
        var quantity: String
    }
    ```
    

**Constants & Extensions**

- **UIViewController+Extensions.swift**
    
    We'll be using a helper function to display alerts. We'll place it the `UIViewController+Extensions.swift` file.
    
    ```swift
    //
    //  UIViewController+Extensions.swift
    //  Restaurant App
    //
    
    import UIKit
    
    extension UIViewController {
    
      func presentAlert(withTitle title: String, message : String) {
        let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
        let OKAction = UIAlertAction(title: "OK", style: .default) { action in
            print("You've pressed OK Button")
        }
        alertController.addAction(OKAction)
        self.present(alertController, animated: true, completion: nil)
      }
    }
    ```
    

- **Constants.swift**
    
    This will hold StoryboardIdentifiers for our ViewControllers, ReuseIdentifiers for our UITableView Cells and some helper enums!
    
    ```swift
    //
    //  Constants.swift
    //  Restaurant App
    //
    
    import Foundation
    
    struct StoryBoardID {
        static let RestaurantListingsViewController = "RestaurantListingsViewController"
        static let RestaurantMenuViewController = "RestaurantMenuViewController"
    }
    
    struct CellIdentifiers {
        static let RestaurantTableViewCell = "RestaurantTableViewCell"
        static let RestaurantMenuTableViewCell = "RestaurantMenuTableViewCell"
    }
    
    enum NetworkState {
        case success
        case loading
        case failure
    }
    ```
    
    Our folder structure would look something like this after the setup:
    
    ![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ruk7k82bgg4v6hvxehj.png) 
    

### Step 3: Setup Restaurant Listings

Create a two new **Cocoa Touch Classes:**

- `RestaurantListingsViewController` of type `UIViewController` to hold our UI
- `RestaurantTableViewCell` of type `UITableViewCell` to customise our **TableCell**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pdn74o3j76tnbivxyaxg.png)
 
Head over to the `Main.storyboard` file where we'll create our view of our controller. 

- Assign **`RestaurantListingsViewController`** class we just created to a new `UIViewController`
- Embed our **`RestaurantListingsViewController`** in an `UINavigationController`
- Configure the UI
    - Loading State UI (When the API call is in progress)
    - Retry State UI (When the API call fails)
    - `RestaurantsTableView` (When the API call succeeds and data is displayed)
    - Create a prototype cell and assign it the `RestaurantTableViewCell` class
    

*You can see the view setup on the interface in the sample project repository [here](https://github.com/canonic-dev/canonic-samples/tree/main/RestaurantApp-iOS)*

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/almpudavdts129h4zr4i.png) 

Head over to `RestaurantListingsViewController` and add the following code. We are going to:

- Create the outlets and connect them with our interface
- Add some variables to hold data for us

```swift
//
//  RestaurantListingsViewController.swift
//  Restaurant-App
//

import UIKit
import Alamofire

class RestaurantListingsViewController: UIViewController {

    var restaurants: [Restaurant] = [] // It'll have the array of all the restaurant items coming from the backend
    var fetchState: NetworkState = .loading // It'll have the latest network state of our view controller to control what to show
    
    @IBOutlet weak var retryButton: UIButton!
    @IBOutlet weak var retryStackView: UIStackView!
    @IBOutlet weak var loadingStackView: UIStackView!
    @IBOutlet weak var restaurantsTableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        title = "Restaurants"

        setupRetryButtton()
        setupTableView()
        
        updateViewState()
        fetchRestaurants()
    }
}
```

Add the following `extensions` below your class to setup our `viewController`:

```swift
// MARK: View Setup

extension RestaurantListingsViewController {
    
		// Sets up the retry button
    fileprivate func setupRetryButtton() {
        retryButton.layer.cornerRadius = 8
        retryButton.configuration?.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20)
    }
    
		// Sets up the tableView
    fileprivate func setupTableView() {
        restaurantsTableView.backgroundColor = .clear
        restaurantsTableView.tableFooterView = UIView()
    }
    
		// Helps to show the correct UI state
    fileprivate func updateViewState() {
        switch fetchState {
        case .success:
            retryStackView.isHidden = true
            loadingStackView.isHidden = true
            restaurantsTableView.isHidden = false
            break;
            
        case .loading:
            retryStackView.isHidden = true
            loadingStackView.isHidden = false
            restaurantsTableView.isHidden = true
            
        case .failure:
            retryStackView.isHidden = false
            restaurantsTableView.isHidden = true
            loadingStackView.isHidden = true
            break
            
        }
    }
}
```

```swift
// MARK: Action Helpers

extension RestaurantListingsViewController {
    
		// Triggers the Restaurant Fetching API call again 
    @IBAction func retryTapped(_ sender: Any) {
        fetchRestaurants()
        updateViewState()
    }
    
		// Updates the TableView after the API Call
    fileprivate func postRestaurantFetchActions() {
        switch fetchState {
        case .success:
            restaurantsTableView.reloadSections(IndexSet(integer: 0), with: .bottom)
            break
        default:
            break
        }
        updateViewState()
    }
    
		// Shows the menu items for the selected restaurant
    fileprivate func pushToRestaurantMenuVC(for restaurant: Restaurant) {
        // Push to Menu Items
    }
}
```

```swift
// MARK: TableView Delegates

extension RestaurantListingsViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {        
        return restaurants.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.RestaurantTableViewCell, for: indexPath) as! RestaurantTableViewCell
        cell.configureCell(for: restaurants[indexPath.row])
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        pushToRestaurantMenuVC(for: restaurants[indexPath.row])
    }
}
```

```swift
// MARK: Networking

extension RestaurantListingsViewController {
    
    fileprivate func fetchRestaurants() {
        fetchState = .loading
        AF.request("YOUR API URL")
          .validate()
          .responseDecodable(of: Restaurants.self) { [weak self] (response) in
            guard let availableRestaurants = response.value else { return }
              self?.restaurants = availableRestaurants.restaurants
              self?.fetchState = (response.error != nil) ? .failure : .success
              DispatchQueue.main.async {
                  self?.postRestaurantFetchActions()
              }
          }
    }
}
```

Head over to `RestaurantTableViewCell` and add the following code to setup our custom cell:

```swift
//
//  RestaurantTableViewCell.swift
//  Restaurant App
//

import UIKit
import Alamofire
import AlamofireImage

class RestaurantTableViewCell: UITableViewCell {
    
    @IBOutlet weak var brandImageView: UIImageView!
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var descriptionLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        brandImageView.contentMode = .scaleToFill
    }

    func configureCell(for restaurant: Restaurant) {
        titleLabel.text = restaurant.name
        descriptionLabel.text = restaurant.description
        
        guard let image = restaurant.brandImage else { return }
        guard let urlString = image.url else { return }
        let request = URLRequest(url: URL(string: urlString)!)
        AF.request(request).responseImage { response in
            if case .success(let image) = response.result {
                self.brandImageView.image = image
                }
        }
    }
}
```

### Step 4: Setup Backend

Let's head to ***Canonic*** and find the `Restaurant App` sample project from the Marketplace. You can either:

- Use this sample project to and continue, or
- Clone it and Deploy 🚀 . This will then use your data from your own project.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pee1prcqmbj43co8oouf.png) 

Head on to the Docs and copy the `/restaurants` endpoint of the Restaurant Table. This is the Get API that will fetch us the data from the database.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/czrwuyqwtlm2qmpxf5i3.png) 

Replace the URL you got in our networking code (`fetchRestaurants` function) in our `RestaurantListingsViewController` file, run the app and it will show you this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ah2wzgrzn5k6kzpaqehm.png) 

### Step 4: Setup Restaurant Menu View

We'll follow a very similar pattern with this `viewController` also.  Create a two new **Cocoa Touch Classes:**

- `RestaurantMenuViewController` ****of type `UIViewController` to hold our UI
- `RestaurantMenuTableViewCell` of type `UITableViewCell` to customise our **TableCell**

Our folder structure will be looking something like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zv7c7c9qnzkydeo1bb4w.png) 

Head over to the `Main.storyboard` file where we'll create our view of our controller. 

- Assign `RestaurantMenuViewController` class we just created to a new `UIViewController`
- Configure the UI
    - Loading State UI (When the API call is in progress)
    - Retry State UI (When the API call fails)
    - Place Order Button
    - `RestaurantsTableView` (When the API call succeeds and data is displayed)
    - Create a prototype cell and assign it the `RestaurantMenuTableViewCell` class
    

*You can see the view setup on the interface in the sample project repository [here](https://github.com/canonic-dev/canonic-samples/tree/main/RestaurantApp-iOS)*

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aae1unncolrk43y2vto1.png) 

Head over to `RestaurantMenuViewController` and add the following code. We are going to:

- Create the outlets and connect them with our interface
- Add some variables to hold data for us

```swift
//
//  RestaurantMenuViewController.swift
//  Restaurant App
//

import UIKit
import Alamofire

// Protocol that our custom cell will confoirm to. It'll be triggered everytime the quantity changes of any of the items
protocol OrderUpdates {
    func updateOrder( menuItem: inout Menu, quantity: Int)
}

class RestaurantMenuViewController: UIViewController {
    
    var restaurant: Restaurant!
    var menuItems: [Menu] = []
    var orderSummary = Order()
    var fetchState: NetworkState = .loading
    
    
    @IBOutlet weak var retryButton: UIButton!
    @IBOutlet weak var retryStackView: UIStackView!
    @IBOutlet weak var loadingStackView: UIStackView!
    @IBOutlet weak var menuTableView: UITableView!
    @IBOutlet weak var placeOrderButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        title = restaurant.name
        orderSummary.restaurant = restaurant.id
        
        setupRetryButtton()
        setupTableView()
        
        updateViewState()
        updatePlaceOrderButton()
        fetchMenu()
    }
}
```

Add the following `extensions` below your class to setup our `viewController`:

```swift
// MARK: View Setup

extension RestaurantMenuViewController {
    
		// Sets up the retry button
    fileprivate func setupRetryButtton() {
        retryButton.layer.cornerRadius = 8
        retryButton.configuration?.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20)
    }
    
// Sets up the tableView
    fileprivate func setupTableView() {
        menuTableView.backgroundColor = .clear
        menuTableView.tableFooterView = UIView()
        menuTableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 100, right: 0)
    }
    
// Helps to show the correct UI state
    fileprivate func updateViewState() {
        switch fetchState {
        case .success:
            retryStackView.isHidden = true
            loadingStackView.isHidden = true
            menuTableView.isHidden = false
            break;
            
        case .loading:
            retryStackView.isHidden = true
            loadingStackView.isHidden = false
            menuTableView.isHidden = true
            break;
            
        case .failure:
            retryStackView.isHidden = false
            menuTableView.isHidden = true
            loadingStackView.isHidden = true
            break;
            
        }
    }
    
}
```

```swift
// MARK: Action Helpers

extension RestaurantMenuViewController {
    
		// Triggers the Menu Fetching API call again
    @IBAction func retryTapped(_ sender: Any) {
        fetchMenu()
        updateViewState()
    }

		// Configures the data and makes and API to the backend to place the order
    @IBAction func placeOrderClicked(_ sender: Any) {
        let jsonData = try! JSONEncoder().encode(orderSummary)
        let json = try? JSONSerialization.jsonObject(with: jsonData, options: [.topLevelDictionaryAssumed]) as? [String: Any]
        let parameters = ["input": json]
        placeOrder(parameters: parameters as [String : Any])
    }
    
		// Updated the Place Order Button with correct amount after the user adds or removes any items
    fileprivate func updatePlaceOrderButton() {
        let amount = getTotalAmount()
        placeOrderButton.setTitle("Place Order: $\(amount)", for: .normal)
        placeOrderButton.setTitle("Place Order", for: .disabled)
        placeOrderButton.isHidden = !(amount > 0.0)
    }
    
		// Updates the TableView after the API Call
    fileprivate func postMenuFetchActions() {
        switch fetchState {
        case .success:
            menuTableView.reloadSections(IndexSet(integer: 0), with: .bottom)
            break
        default:
            break
        }
        updateViewState()
    }
    
		// Heleper function to get the price of an menu item
    fileprivate func getItemPrice(itemId: String) -> Double {
        let item = menuItems.first { item in
            item.id == itemId
        }
        
        return (Double(item!.price) ?? 0.0)
    }
    
		// Heleper function to get the total that amounts up after adding the items
    fileprivate func getTotalAmount() -> Double {
        return orderSummary.orderItems.reduce(0.0) { result, orderItem in
            result + (getItemPrice(itemId: orderItem.item) * (Double(orderItem.quantity) ?? 0.0))
        }
    }
}
```

```swift
// MARK: TableView Delegates

extension RestaurantMenuViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return menuItems.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.RestaurantMenuTableViewCell, for: indexPath) as! RestaurantMenuTableViewCell
        cell.delegate = self
        cell.selectionStyle = .none
        cell.configureCell(for: menuItems[indexPath.row])
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }
}
```

```swift
// MARK: Order Update Delegates

extension RestaurantMenuViewController: OrderUpdates {
    
    internal func updateOrder( menuItem: inout Menu, quantity: Int) {
        if let row = orderSummary.orderItems.firstIndex(where: {$0.item == menuItem.id}) {
            if (quantity == 0) {
                orderSummary.orderItems.remove(at: row)
            } else {
                orderSummary.orderItems[row].quantity = "\(quantity)"
            }
        } else {
            orderSummary.orderItems.append(OrderItems(item: menuItem.id, quantity: "\(quantity)"))
        }
        
        orderSummary.totalAmount = "\(getTotalAmount())"
        updatePlaceOrderButton()
    }
}
```

```swift
// MARK: Networking

extension RestaurantMenuViewController {
    
    fileprivate func fetchMenu() {
        fetchState = .loading
        AF.request("https://restaurant-app.can.canonic.dev/api/menus")
            .validate()
            .responseDecodable(of: Menus.self) { [weak self] (response) in
                guard let availableMenus = response.value else { return }
                self?.menuItems = availableMenus.menus
                self?.fetchState = (response.error != nil) ? .failure : .success
                DispatchQueue.main.async {
                    self?.postMenuFetchActions()
                }
            }
    }
    
    fileprivate func placeOrder(parameters: [String: Any]) {
        fetchState = .loading
        updateViewState()
        AF.request("https://restaurant-app.can.canonic.dev/api/orders", method: .post, parameters: parameters as Parameters, encoding: JSONEncoding.default)
            .responseData { [weak self] response in
                if ((response.value) != nil) {                    
                    DispatchQueue.main.async {
                        self?.presentAlert(withTitle: "Order Placed 🥳", message: "Sit Tight, your order has been received!")
                        self?.orderSummary = Order()
                        self?.orderSummary.restaurant = (self?.restaurant.id)!
                        self?.updatePlaceOrderButton()
                        self?.fetchState = .success
                        self?.updateViewState()
                        self?.menuTableView.reloadSections(IndexSet(integer: 0), with: .bottom)
                    }
                } else {
                    DispatchQueue.main.async {
                        self?.presentAlert(withTitle: "Oops!", message: "Something went wrong, try again later!")
                        self?.updateViewState()
                        self?.fetchState = .failure
                    }
                }
            }
    }
}
```

Head over to `RestaurantMenuTableViewCell` and add the following code to setup our custom cell:

```swift
//
//  RestaurantMenuTableViewCell.swift
//  Restaurant App
//

import UIKit
import Alamofire
import AlamofireImage

class RestaurantMenuTableViewCell: UITableViewCell {
    
    @IBOutlet weak var itemImageView: UIImageView!
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var descriptionLabel: UILabel!
    @IBOutlet weak var priceLabel: UILabel!
    @IBOutlet weak var quatityLabel: UILabel!
    @IBOutlet weak var stepper: UIStepper!
    
    var menuItem: Menu = Menu()
    var delegate: OrderUpdates?
    
    override func awakeFromNib() {
        super.awakeFromNib()
        itemImageView.contentMode = .scaleToFill
    }
    
    @IBAction func stepperClicked(_ sender: UIStepper) {
        quatityLabel.text = "x\(String(format: "%.0f", sender.value))"        
        delegate?.updateOrder(menuItem: &menuItem, quantity: Int(sender.value))
    }
    
    func configureCell(for menu: Menu) {
        menuItem = menu
        titleLabel.text = menu.itemName
        descriptionLabel.text = menu.description
        priceLabel.text = "$\(menu.price)"
        quatityLabel.text = "x\(String(format: "%.0f", stepper.value))"
        
        
        guard let image = menu.itemImage else { return }
        guard let urlString = image.url else { return }

        let request = URLRequest(url: URL(string: urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!)!)
        AF.request(request).responseImage { response in
            if case .success(let image) = response.result {
                self.itemImageView.image = image
            }
        }
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
        itemImageView.image = nil
    }
}
```

### Step 5: Take the user to the Menu Listing

Now both of our `viewControllers` are set. Let's add the code to push the user to the menu listings when the user clicks on any restaurant. Head to `RestaurantListingsViewController` and update the `pushToRestaurantMenuVC` function:

```swift
fileprivate func pushToRestaurantMenuVC(for restaurant: Restaurant) {
        let restaurantMenuVC = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: StoryBoardID.RestaurantMenuViewController) as! RestaurantMenuViewController
        restaurantMenuVC.restaurant = restaurant
        self.navigationController?.pushViewController(restaurantMenuVC, animated: true)
    }
```

Build and run your app to see it in action 🥳 Now when you click on the it'll fetch the menu items of the restaurant and let you place your order.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ltusfc2gvvjbkplxv43.png)

And with that, you have successfully made a basic Food Ordering iOS App for your project. 💃🕺

Congratulations! 🎉

---

If you want, you can also duplicate this project from Canonic's sample app and easily get started by customizing it as per your experience. Check it out [app.canonic.dev](http://app.canonic.dev/).

You can also check out our other guides [here](https://dev.to/canonic).

Join us on discord to discuss or share with our community. Write to us for any support requests at [support@canonic.dev](mailto:support@canonic.dev). Check out our [website](http://www.canonic.dev/) to know more about Canonic.