Table views are a lot like potato chips: You can’t have just one. Often, table views relate to each other in what is often referred to as a drill-down. Drill downs typically take the selected data and provide another list in a table about the selection. It creates a hierarchical selection. You might have a list of car manufacturers for example. From that list you select one manufacturer, which gives you a list of models that manufacturers makes. Click on a model and you might get details about the car. I’ve gotten more questions about drill-down than any other topic, mostly along the lines of “how do I program my table view to…” I’ve given short answers, but I want to give the long one. It really has nothing to do with the table view controllers. It has to do with the models.
For this lesson, we’ll explore ways of getting to that result. This lesson will require skills on building classes, dictionaries, and table views. If you do not understand something you might want to refer to these lessons:
- Table views:Introducing table Views
- Dictionaries:How to use Dictionaries in Swift
- Classes and Computed Properties:A Swift Guide to Working with Classes Part One and Part two
A Look at Some Data
Table views are actually quite simple-minded by design. They can handle data from a simple array and not more than that. Our sophistication with table views happens not in the controller, but in the model. How we handle our data and present it to the controller is key to good design of table views. For most cases, these models are generated from some form of persistent data source, such as a data file, Core Data or SQLite. You may have more then one source of data you want to associate with each other as well. Lets take as an example two data tables. The first table lists foods and the meal it is eaten.
Food | Meal |
---|---|
Pizza | Lunch |
Pasta | Lunch |
Chocolate Mousse | Dessert |
Oatmeal | Breakfast |
Pancakes | Breakfast |
Peanut Butter and Jelly | Lunch |
Mole con Pollo | Dinner |
Hamburger | Lunch |
Pad Thai | Dinner |
Paneer | Dinner |
Chocolate Chip Cookie | Snack |
Tuna Salad Sandwich | Lunch |
Bagel | Breakfast |
The second table lists foods, prices and calorie counts
Food | Price | Calories |
---|---|---|
Pizza | 4.99 | 317 |
Pasta | 7.99 | 325 |
Chocolate Mousse | 6.45 | 470 |
Oatmeal | 2.95 | 160 |
Pancakes | 3.95 | 470 |
Peanut Butter and Jelly | 1.99 | 319 |
Pollo con Mole | 8.50 | 860 |
Hamburger | 4.35 | 250 |
Pad Thai | 7.35 | 430 |
Paneer | 6.99 | 100 |
Sirloin Steak | 24.49 | 165 |
Chocolate Chip Cookie | 2.75 | 210 |
Tuna Salad Sandwich | 3.25 | 420 |
Bagel | 1.50 | 275 |
What we would like to have is a table view that lists meals
When we select a meal, the app lists those foods.
When we select a food, it displays price and calorie information about that food.
How do we code this?
Set Up the Application
Let’s go through a few different options for doing drill-downs. We’ll need two table views and a view controller. Make a new Xcode single view project DrillDownTables. Make Swift the language and keep the application Universal. Save the project.
The Launchscreen
In the navigator, click the Launchscreen.storyboard file. We’ll need to set up our own launch screen. For most demo and practice apps, I just center a line of text on a label. Drag a label out on the storyboard. Change the text to Drill Down Tables. With the label selected, click the align menu on the bottom right of the storyboard. Click on Horizontally in Container and Vertically in Container. Make sure the values for both are 0. Select Items of New constraints for update frames
I usually change the background color as well, this time to #EEFFDD but that is to taste.
Make the Storyboard
We have a bit of work setting up the storyboard, but we only have to do it once for several iterations of the application. Drag a table view controller to the storyboard. In the attributes inspector for the table view controller, under View Controller check on Is Initial View Controller. In the drop down menu, select Editor>Embed in>Navigation Controller . Double-click the navigation bar on the top of the table view controller and title the controller Meals. Drag the original view controller out of the way for now.
Select the tableview and make sure it says Dynamic Prototypes. If you wish you can set a background color, scroll down to view and setting the color. I set a pale yellow (#FFFFCC) for the background.
Select the table view cell. Set the identifier to cell. Set the accessory indicator to Disclosure.
Press Command-N and make a new Cocoa Touch Class subclassing NSObject
named MealsTableViewController. I prefer to build table view controllers from scratch to keep a lot of the extra methods in the templates out of the way. NSObject
gives a nice blank slate. Save the file and make sure it is in the DrillDownTables folder group. When it opens, change NSObject
to UITableViewController
so you get this:
class MealsTableViewController: UITableViewController { }
Go back to the storyboard. Select the Meals View Controller icon. in the identity inspector, set the class to MealsTableViewController
.
The Food Table
Drag another table view controller on to the storyboard. Control-drag from the cell in the Meals view controller to the new view controller. Select a show Segue. Set the segue Identifier to Foods.
Select the tableview and make sure it says dynamic prototypes. I’m in a bit of a pastel mood, so I set a peachy color (#FFDDCC) for the background.
Set the table view cell’s identifier cell. Set the Accessory to Disclosure.
Press Command-N and make a new Cocoa Touch Class subclassing NSObject
named FoodsTableViewController. Save the file and make sure it is in the DrillDownTables folder group. When it opens, change NSObject
to UITableViewController
so you get this:
class FoodsTableViewController: UITableViewController { }
Go back to the storyboard. Select the View Controller icon for the second table. In the identity inspector, set the class to FoodsTableViewController
.
The Info View Controller
Control-Drag from the table cell in the Foods view controller to the orphaned view controller from earlier. Select a show Segue. Set the segue Identifier to Info. I set something bluish (#DDEEFF) for the background.
Drag two labels onto the story board, labeling them Calories and Price. Drag Price above Calories. Using autolayout, pin the Price label 20 points up, 0 points left and 0 points right. For Update Frames select Items of New Constraints
Pin the Calories label the same way: 20 points up, 0 points left and 0 points right. For Update Frames select Items of New Constraints. You should have something like this:
Press Command-N and make a new Cocoa Touch Class subclassing UIViewController
named InfoViewController. Save the file making sure it is in the DrillDownTables folder group. You will only need viewDidload
so you can delete everything else in the class.
Go back to the storyboard. Select the view controller icon for this last scene. In the identity inspector, set the class to InfoViewController
.
Open the assistant editor. Control-drag from the Price label and make an outlet named priceLabel. Control drag from the Calories label and make an outlet caloriesLabel. Close the Assistant editor.
Make the First Model
Our first goal is to get a working table view. We’ll just list what we need in each of the models first, to make sure the table reads it right.
A List of Meals
Press Command-N and make a new Swift Cocoa Touch file Subclassing NSObject
named MealModel
. Code the class like this:
class MealModel{ var meal:[String] = [ "Breakfast", "Lunch", "Dinner"] }
A List of Foods
Our second table is our foods table. For right now we’ll list all the foods in the table to make sure everything in the view controller is working. We’ll use a dictionary to make this table. Press Command-N and make a new Swift Cocoa Touch file Subclassing NSObject
named FoodsModel
. Code the class like this:
class FoodsModel { var foodList:[String:String] = [ "Pizza":"Lunch", "Pasta":"Lunch", "Chocolate Mousse":"Dessert", "Oatmeal":"Breakfast", "Pancakes":"Breakfast", "Peanut Butter and Jelly":"Lunch", "Mole con Pollo":"Dinner", "Hamburger":"Lunch", "Pad Thai":"Dinner", "Paneer":"Dinner", "Sirloin Steak":"Dinner", "Chocolate Chip Cookie":"Snack", "Tuna Salad Sandwich":"Lunch", "Bagel":"Breakfast" ] func foods(meal:String) -> [String]{ return Array(foodList.keys) } }
This model uses a dictionary with the food as a unique key, and the meal as a value. For the table view, we still need an array. We made the function foods
to get the array. We don’t use the parameter — yet. I did that so we don’t have to change it later.
We are not going to use the Info view controller just yet. We want to get our tables working first.
Coding our Tables
We have some models to work with. Before we work with the models in more sophisticated ways, it helps to set up the tables and make sure they are working correctly.
Coding the Meals Table
Go to MealTableviewController
. Add the model as a property to our blank class:
let meals = MealModel()
We need three data source methods in our table. First add this:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return meals.meal.count }
We have one section and we will take the number of elements of the array meals.meal
for the number of rows. Add the cellForRowAtIndexPath
data source
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) let row = indexPath.row cell.textLabel?.text = meals.meal[row] return cell }
The code gets the cell, then the row in the index, since we only have one section. We take the property meal
and use the row to determine which element of that array we use.
Coding the Foods Table
Go to FoodsTableviewController
. Add the model as a property to our blank class and an array to store the foods from the model:
let foodsModel = FoodsModel() var meal = "Lunch" var foods = [String]()
initialize foods by adding a viewDidLoad
to the class:
override func viewDidLoad() { super.viewDidLoad() foods = foodsModel.foods(meal) }
We need those three data source methods in our table. First add the table size ones:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return foods.count }
Add the cellForRowAtIndexPath
data source
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) let row = indexPath.row cell.textLabel?.text = foods[row] if (row % 2) == 0 { //alternate rowcolors cell.backgroundColor = UIColor.clearColor() cell.textLabel?.textColor = UIColor.blackColor() } cell.alpha = 0.75 return cell }
This time I added a little spice, as the rows will alternate colors. I decide that by getting the modulo of the row divided by two. It can be either 1 or 0, If 0, I change the color.
Coding the Food Info View
In the Info view controller, we are not yet going to use a model, but set up the controller a bit. Go to the InfoController
, add the following property:
var food = "Food Info" // Key
Change the viewDidLoad
to this:
override func viewDidLoad() { super.viewDidLoad() navigationItem.title = food }
We’ll set the food name as our navigation title.
Build and run. On the first screen you should get the three meals.
Select a meal. You should see all the foods.
You can select a food, and not much will happen besides a title. We havent programmed our segues yet.
Adding Segues
Go to MealsTableViewController
. Add a prepareForSegue
method
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "Foods"{ let vc = segue.destinationViewController as! FoodTableViewController let selectedMeal = meals.meal[(tableView.indexPathForSelectedRow?.row)!] vc.meal = selectedMeal vc.navigationItem.title = selectedMeal } }
We send the selected meal to the next controller, setting its title and the meal
property. Go to the FoodsTableViewController
. Add this prepareForSegue
method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { let selectedRow = (tableView.indexPathForSelectedRow?.row)! if segue.identifier == "Info"{ let vc = segue.destinationViewController as! InfoViewController vc.food = foods[selectedRow] } }
In both of these controllers, we use the indexPathForSelectedRow
property to get the index path of the row selected, and use the data from that row to send to the destination controller.
Build and run. Our selection reflect on the next view’s navigation title, but not the food selection.
Select a food to go to the Info scene and the food shows on the Navigation bar title
Iteration 1: Coding with a Dictionary
Much of what we need is already set up. The MealsTableViewController
is already sending the selected meal to the FoodsTableViewController
. We have to do something with it. The long list of foods needs to be a short list of foods for only that meal. Comment out the current foods
and replace with this:
//linear search for all food with a given meal func foods(meal:String) -> [String]{ var shortList:[String] = [] for food in Array(foodList.keys){ if foodList[food] == meal{ shortList += [food] } } return shortList }
This performs a linear search for all foods for that meal. It returns the list for that have meal
for a value. Build and run. Select Breakfast. You get breakfast foods.
A One to Many Table
Notice something about our table though: We have a one to one relationship between the meal and the food. Using this code I can only have a Hamburger for lunch or dinner, but not both.
The key of the dictionary is the food, not the meal. We need a unique key for the meal, and then a list of foods. In the MealsModel.swift file, comment out the current model and add this for the class:
class MealModel { var mealList = [String:[String]]() }
This makes a dictionary where we have a meal for a key and a array of foods associated with the food.
To get the meals, we can add the following computed property
var meal:[String]{ get{ return Array(mealList.keys) } }
To make it easier to add items to the model, add an addItem
method:
func addItem(meal:String,foods:[String]){ mealList[meal] = foods }
We’ll initialize the class with slightly different data. Add the following:
init(){ //what we do here would usually be a database or file access addItem("Breakfast", foods: [ "Oatmeal", "Pancakes", "Bagel" ]) addItem("Lunch", foods: [ "Pizza", "Pasta", "Peanut Butter and Jelly", "Tuna Salad Sandwich", "Hamburger"]) addItem("Dinner", foods: [ "Mole con Pollo", "Pad Thai", "Paneer", "Sirloin Steak", "Pizza", "Pasta", "Hamburger" ]) addItem("Snack", foods: [ "Chocolate Chip Cookie", "Pizza" ]) }
We have a list of foods. We added Snack, and removed the orphan dessert chocolate mousse. A hamburger is now a lunch and dinner food. Pizza is a lunch, dinner, and nack food. We have a one to many relationship.
We need only one more thing to complete this new class. Add the following code:
func foods(meal:String) -> [String]{ //for use with the model if let list = self.mealList[meal]{ return list } else { return [] } }
Notice the code is a lot simpler in this version of foods
, since we use a dictionary property. We just check if the dictionary exists using optional chaining then return our food list. If no entry, return an empty array
Changing the FoodModel
The class FoodModel
has a lot less to do. I could remove it completely, but in a real application there may be things I do to a selected list of foods that I won’t do to the entire list. Comment out the current FoodModel
class and add this class after it
/* Second Iteration of the model */ class FoodsModel{ var foodList:[String] = [] func foods(meal:String) ->[String]{ return foodList } }
We have in this model version a string array for the list of foods. If we assume MealsModel sends the list of selected foods to this model, we only have to return the value.
Coding the Tables
The beautiful thing about MVC is that if we use the same properties and methods in two classes we can swap them out easily. Our new versions of FoodsModel
and MealsModel
need very few changes. FoodsModel
works exactly the same from the table view controllers view, though the meal
parameter is once again redundant. We have to change only one thing in the meals table for these models. We added the foods
function to the MealsModel
. We will use that to load the FoodsModel
in our prepareForSegue
like this:
vc.foodsModel.foodList = meals.foods(selectedMeal)
In the MealsTableViewController
, change prepareForSegue
to this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "Foods"{ let vc = segue.destinationViewController as! FoodsTableViewController let selectedMeal = meals.meal[(tableView.indexPathForSelectedRow?.row)!] vc.meal = selectedMeal vc.navigationItem.title = selectedMeal vc.foodsModel.foodList = meals.foods(selectedMeal) }
Build and run. Select Lunch,
Go back to the menu and Select Dinner
Hamburger and pizza show up in both.
Coding the Info Model
We’ve been ignoring the last view controller. While we’ve been drilling down, we have not gotten to any detail about our foods. At some point we will need to work with data. In our example, it is calorie and price information. In Xcode, press Command-N and make one more class subclassing NSObject
called FoodInfoModel. Above the FoodInfoModel class, add this class:
class FoodItemInfo{ // the record or row of the database var name = "" var price = 0.00 var calories = 0 init(name:String,price:Double,calories:Int){ self.name = name //primary key self.price = price self.calories = calories } }
If you think in database terms, this is our record or row. We’ll use this in the dictionary we’ll create in FoodInfoModel
to hold our data. Add this to the FoodInfoModel
class:
var list = [String:FoodItemInfo]() func addItem(key:String,price:Double,calories:Int){ let foodItem = FoodItemInfo( name: key, price: price, calories: calories) list[key] = foodItem //this modifies or adds to the file }
He’s our dictionary of info with a key of a food item’s name. We have one seeming redundancy: name
is the key, and is a property in the FoodItemInfo
class. I may pass the FoodItemInfo
somewere without the key, and so I’d like to keep the name handy. The method addItem
adds the record for a food to our dictionary. I could do use FoodItemInfo’s initializer for each food item to load my dictionary:
list["Pizza"] = FoodItemInfo("Pizza", price: 4.99, calories: 317)
However, addItem
is better documentation and is less keystrokes. Add the following to the end of the FoodInfoModel
:
init(){ // this would normally be a loaded file // or Database from SQL or Core Data addItem("Pizza", price: 4.99, calories: 317) addItem("Pasta", price: 7.99, calories: 325) addItem("Chocolate Mousse", price: 6.45, calories: 470) addItem("Oatmeal", price: 2.95, calories: 160) addItem("Pancakes", price: 3.95, calories: 470) addItem("Peanut Butter and Jelly", price: 1.99, calories: 319) addItem("Pollo con Mole", price: 8.50, calories: 860) addItem("Hamburger", price: 4.35, calories: 250) addItem("Pad Thai", price: 7.35, calories: 430) addItem("Paneer", price: 6.99, calories: 100) addItem("Sirloin Steak", price: 24.49, calories: 165) addItem("Chocolate Chip Cookie", price: 2.75, calories: 210) addItem("Tuna Salad Sandwich", price: 3.25, calories: 420) addItem("Bagel", price: 1.50, calories: 275) }
Our data will now load when we initialize the class.
Coding The Info View Controller
We’ll use the key:value
coding of dictionareis again to find and access information about a certain food. Dictionary access returns an optional value, so we’ll check for nil
using optional chaining. If there is a value, we’ll display it. If not, we’ll display that it wasn’t found in our database. Add the following to InfoViewController
:
var foodInfoModel = FoodInfoModel() //our model func displayFoodInfo(){ if let foodInfo = foodInfoModel.list[food]{ caloriesLabel.text = String(format:"%i Calories",foodInfo.calories) priceLabel.text = String(format:"Price: %1.2f",foodInfo.price) } else { caloriesLabel.text = "Not Found" priceLabel.text = "Not Found" } }
We’ll display the info when we load the view controller. Change viewDidLoad
to this:
override func viewDidLoad() { super.viewDidLoad() navigationItem.title = food displayFoodInfo() }
Build and run. In Lunch, select Peanut butter and jelly
This demo app worked with literal values we added in the init()
of a class. In a real app, it’s likely that these would be SQLite databases, files or Core Data. Actually implementing them in an app is more than few lessons in themselves, so I went with this easier method. Once you understand this concept, you might want to learn about persistent storage of some kind.
The Whole Code
Note in the code below I did not format for web readability. I assume this will be code cut and pasted to Xcode, so left it in the standard format, with the exception of adding data to the arrays and dictionaries.
MealModel.swift
// // MealModel.swift // DrillDownTableDemo // // Created by Steven Lipton on 10/5/15. // Copyright © 2015 MakeAppPie.Com. All rights reserved. // import UIKit /* first iteration of model class MealModel{ //first iteration for testing var meal:[String] = [ "Breakfast", "Lunch", "Dinner"] } */ /* Second iteration of model */ class MealModel { var mealList = [String:[String]]() var meal:[String]{ get{ return Array(mealList.keys) } } func addItem(meal:String,foods:[String]){ //adds an item to the dictionary if not there //side effect: changes current elements in dictionary mealList[meal] = foods } func foods(meal:String) -> [String]{ //for use with the model if let list = self.mealList[meal]{ return list } else { return [] } } /* Load data into the model Note that this would normally be some external load from a file or database For this lesson we are loading it literally */ init(){ addItem("Breakfast", foods: [ "Oatmeal", "Pancakes", "Bagel" ]) addItem("Lunch", foods: [ "Pizza", "Pasta", "Peanut Butter and Jelly", "Tuna Salad Sandwich", "Hamburger" ]) addItem("Dinner", foods: [ "Mole con Pollo", "Pad Thai", "Paneer", "Sirloin Steak", "Pizza", "Pasta", "Hamburger" ]) addItem("Snack", foods: [ "Chocolate Chip Cookie", "Pizza" ]) } }
FoodsModel.swift
// // FoodsModel.swift // DrillDownTableDemo // // Created by Steven Lipton on 10/5/15. // Copyright © 2015 MakeAppPie.Com. All rights reserved. // import UIKit /* First Iteration of the model class FoodsModel { var foodList:[String:String] = [ "Pizza":"Lunch", "Pasta":"Lunch", "Chocolate Mousse":"Dessert", "Oatmeal":"Breakfast", "Pancakes":"Breakfast", "Peanut Butter and Jelly":"Lunch", "Mole con Pollo":"Dinner", "Hamburger":"Lunch", "Pad Thai":"Dinner", "Paneer":"Dinner", "Sirloin Steak":"Dinner", "Chocolate Chip Cookie":"Snack", "Tuna Salad Sandwich":"Lunch", "Bagel":"Breakfast" ] /* func foods(meal:String) -> [String]{ return Array(foodList.keys) } */ //linear search for all food with a given meal func foods(meal:String) -> [String]{ var shortList:[String] = [] for food in Array(foodList.keys){ if foodList[food] == meal{ shortList += [food] } } return shortList } }*/ /* Second Iteration of the model */ class FoodsModel{ var foodList:[String] = [] func foods(meal:String) ->[String]{ return foodList } }
FoodInfoModel.swift
// // FoodInfoModel.swift // drillDownTable // // Created by Steven Lipton on 10/1/15. // Copyright © 2015 MakeAppPie.Com. All rights reserved. // import UIKit class FoodItemInfo{ // the record or row of the database var name = "" var price = 0.00 var calories = 0 init(name:String,price:Double,calories:Int){ self.name = name //primary key self.price = price self.calories = calories } } class FoodInfoModel{ // the file of the database var list = [String:FoodItemInfo]() func addItem(key:String,price:Double,calories:Int){ let foodItem = FoodItemInfo(name: key, price: price, calories: calories) list[key] = foodItem //this modifies or adds to the file } init(){ // this would normally be a loaded file // or Database from SQL or Core Data addItem("Pizza", price: 4.99, calories: 317) addItem("Pasta", price: 7.99, calories: 325) addItem("Chocolate Mousse", price: 6.45, calories: 470) addItem("Oatmeal", price: 2.95, calories: 160) addItem("Pancakes", price: 3.95, calories: 470) addItem("Peanut Butter and Jelly", price: 1.99, calories: 319) addItem("Pollo con Mole", price: 8.50, calories: 860) addItem("Hamburger", price: 4.35, calories: 250) addItem("Pad Thai", price: 7.35, calories: 430) addItem("Paneer", price: 6.99, calories: 100) addItem("Sirloin Steak", price: 24.49, calories: 165) addItem("Chocolate Chip Cookie", price: 2.75, calories: 210) addItem("Tuna Salad Sandwich", price: 3.25, calories: 420) addItem("Bagel", price: 1.50, calories: 275) } }
MealsTableViewController.swift
// // MealsTableViewController.swift // DrillDownTableDemo // // Created by Steven Lipton on 10/4/15. // Copyright © 2015 MakeAppPie.Com. All rights reserved. // import UIKit class MealsTableViewController: UITableViewController { let meals = MealModel() //MARK: Table View Datasources override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return meals.meal.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) let row = indexPath.row cell.textLabel?.text = meals.meal[row] return cell } //MARK: Life Cycle override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if segue.identifier == "Foods"{ let vc = segue.destinationViewController as! FoodsTableViewController let selectedMeal = meals.meal[(tableView.indexPathForSelectedRow?.row)!] vc.meal = selectedMeal vc.navigationItem.title = selectedMeal vc.foodsModel.foodList = meals.foods(selectedMeal) } } }
FoodsTableViewController.swift
// // FoodsTableViewController.swift // DrillDownTableDemo // // Created by Steven Lipton on 10/4/15. // Copyright © 2015 MakeAppPie.Com. All rights reserved. // import UIKit class FoodsTableViewController: UITableViewController { let foodsModel = FoodsModel() var meal = "Lunch" var foods = [String]() //MARK: Table View Data Sources override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return foods.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) let row = indexPath.row cell.textLabel?.text = foods[row] if (row % 2) == 0 { //alternate rowcolors cell.backgroundColor = UIColor.clearColor() cell.textLabel?.textColor = UIColor.blackColor() } cell.alpha = 0.75 return cell } //MARK: Life Cycle override func viewDidLoad() { super.viewDidLoad() foods = foodsModel.foods(meal) } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { let selectedRow = (tableView.indexPathForSelectedRow?.row)! if segue.identifier == "Info"{ let vc = segue.destinationViewController as! InfoViewController vc.food = foods[selectedRow] } } }
InfoViewController.swift
// // InfoViewController.swift // DrillDownTableDemo // // Created by Steven Lipton on 10/5/15. // Copyright © 2015 MakeAppPie.Com. All rights reserved. // import UIKit class InfoViewController: UIViewController { @IBOutlet weak var priceLabel: UILabel! @IBOutlet weak var caloriesLabel: UILabel! var food = "Food Info" var foodInfoModel = FoodInfoModel() //our model func displayFoodInfo(){ if let foodInfo = foodInfoModel.list[food]{ caloriesLabel.text = String(format:"%i Calories",foodInfo.calories) priceLabel.text = String(format:"Price: %1.2f",foodInfo.price) } else { caloriesLabel.text = "Not Found" priceLabel.text = "Not Found" } } override func viewDidLoad() { super.viewDidLoad() navigationItem.title = food displayFoodInfo() } }
Leave a Reply