0

I am using web api for food names and foodCategories. How can I match my breakfasts category section only with breakfasts, burgers, desserts, drinks, salads. Problem is each section has all foods again and again.

FoodCategory

struct FoodCategory: Decodable {
var id: Int
var Title: String //Category Title
}

Food category title is in two models both.

Food

struct Food: Codable {
    let id, SubCategoryId: Int
    let CategoryTitle: String //Category Title
    let Price, OldPrice: Decimal
    let ProductTitle: String //Food Name
    let Stock: Int
    let Details: String
    let DetailsList: [String]
}

FoodCategoryServiceResponse

   "ResultList": [
    {
        "id": 1,
        "Title": "Kahvaltılar"
    },
    {
        "id": 5,
        "Title": "Hamburgerler"
    },
    {
        "id": 6,
        "Title": "İçecekler"
    },
    {
        "id": 7,
        "Title": "Tatlılar"
    },
    {
        "id": 9,
        "Title": "Salatalar"
    }
   ]

FoodServiceResponse

"ResultList": [
{
"id": 114,
"SubCategoryId": 28,
"SubCategoryTitle": "Hafta İçi Kahvaltısı",
"CategoryTitle": "Kahvaltılar",
"Title": null,
"Price": 18,
"OldPrice": 0,
"PriceString": " 18,00  ₺",
"OldPriceString": " 0,00  ₺",
"ProductTitle": "Hafta İçi Kahvaltısı",
"IsIndexView": false,
"Description": "Ekmek Üzeri Çırpılmış Yumurta, 1 Dilim Beyaz Peynir, Çilek Reçeli, 1 Bardak Çay",
"Stock": 0,
} ]

Tableview codes

 var foodData = [Food]() 
    var foodCategoryData = [FoodCategory]()

 func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return foodCategoryData[section].Title
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return foodCategoryData.count
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return foodData.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "CellForFood") as! MainFoodTitleTableViewCell
        let foodList = foodData[indexPath.row]
        //        let food = foods.filter({$0.category == sections[indexPath.section]})[indexPath.row]
        cell.titleLabel.text = foodList.ProductTitle
        cell.priceLabel.text = foodList.PriceString

        return cell
    }
Emre Değirmenci
  • 715
  • 6
  • 22

2 Answers2

1

I recommend to use two structs as data model

struct Category {
    let name : String
    let foods : [Food]
}

struct Food {
    let name : String
    let price : Double
}

let categories = [
    Category(name: "Breakfast", foods : [
        Food(name: "Hafta İçi Kahvaltısı", price: 18.0),
        Food(name: "Pazar Kahvaltısı", price: 25.0),
        Food(name: "Diyet Kahvaltı", price: 22.0),
        Food(name: "Köy Kahvaltısı", price: 15.0),
        Food(name: "Ege Kahvaltısı", price: 30.0)]),
    Category(name: "Hamburger", foods : [
        Food(name: "Big TezBurger", price: 26.0),
        Food(name: "TezRoyal", price: 24.0),
        Food(name: "Double TezzBurger", price: 17.0),
        Food(name: "TezChicken", price: 21.0),
        Food(name: "Köfteburger", price: 28.0)])
]

This reduces the code in the table view data source and delegate methods considerably

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return categories[section].name
}

func numberOfSections(in tableView: UITableView) -> Int {
    return categories.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return categories[section].foods.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "CellForFood", for: indexPath) as! MainFoodTitleTableViewCell

    let category = categories[indexPath.section]
    let food = category.foods[indexPath.row]    
    cell.title = food.name
    cell.price = food.price
    return cell
}

Your code in cellForRowAt makes no sense anyway. This method is called once for each row in each section.

vadian
  • 274,689
  • 30
  • 353
  • 361
  • Sorry, you messed up the entire question. Please revert it to the last version and ask a new question. And please read my answer carefully to understand how to get the items in `cellForRow` depending on section and row. – vadian Jun 12 '19 at 17:04
  • I tried like your `let categories = []` code block. If I fill my category names like yours it is okay because there is only 5 static datas for categories. But if I use foods object in `Category' struct like yours I should initialize with static data also. foods object has a lot of property and it gets messy. – Emre Değirmenci Jun 12 '19 at 17:22
  • If you have static data organize it in a Property List or JSON file in the application bundle and load the data with `PropertyListDecoder()` or `JSONDecoder()`. That's pretty fast and pretty clean. – vadian Jun 12 '19 at 17:26
  • Yes it is so meaningful recommendation. But I tried your recommendation for saving my table view data for logged in user's shopping cart and I did not success. After I tried with `CoreData` and also did not success. Because I am awkward person. https://stackoverflow.com/questions/56509495/how-to-save-existing-singleton-table-view-data-in-core-data – Emre Değirmenci Jun 12 '19 at 17:49
0

Create an array that represents your sections

let sections = ["Breakfast", "Hamburger", "Drinks", "Dessert", "Salad"]

Then change your functions to

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return sections[section]
}

func numberOfSections(in tableView: UITableView) -> Int {
    return sections.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let sectionName = sections[section]
        return foods.filter({ $0.category == sectionName }).count

}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "CellForFood") as! MainFoodTitleTableViewCell

    food = foods.filter({ $0.name == sections[indexPath.section] })[indexPath.row]
    cell.title = food.name
    cell.price = food.price

    return cell
}
AgRizzo
  • 5,261
  • 1
  • 13
  • 28
  • Fatal error: index out of range on this line `food = foods.filter({ $0.name == sections[indexPath.section] })[indexPath.row]` @agrizzo – Emre Değirmenci May 10 '19 at 19:39