Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Populating table Swift - What am I doing wrong?

Doing another random practice app and am having trouble trying to populate a tableview where the "name" shows in every row from a struct.

Here is my library:

import Foundation

struct BenchmarkWODs {

    let library = [
        [
            "name": "Angie",
            "exercises": "100 Pull-ups/n100 Push-ups/n100 Sit-ups/n100 Squats",
            "description": "For Time Complete all reps of each exercise before moving to the next."
        ],
        [
            "name": "Barbara",
            "exercises": "20 Pull-ups\n30 Push-ups\n40 Sit-ups50 Squats\n\nRest precisely three minutes between each round.",
            "description": "5 rounds, time each round"
        ]
]
}

There are more than two listings within it but you get the drift. Below is my detail file:

import Foundation
import UIKit

struct WODList {

    var name: String?
    var exercise: String?
    var description: String?

    init(index: Int) {
        let benchmarkWODLibrary = BenchmarkWODs().library
        let benchmarkDictionary = benchmarkWODLibrary[index]

        name = benchmarkDictionary["name"] as String!
        exercise = benchmarkDictionary["exercises"] as String!
        description = benchmarkDictionary["description"] as String!

    }

}

Lastly, below is my view controller file for the tableview.

import UIKit

class BenchmarkWODViewController: UITableViewController {

    var wodList = WODList?()



    override func viewDidLoad() {
        super.viewDidLoad()


    }



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

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

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
        {
            let cell = tableView.dequeueReusableCellWithIdentifier("BenchmarkCell", forIndexPath: indexPath)

            //let WODTitle = wodList?.name
            cell.textLabel?.text = self.wodList?.name


            return cell
        }


}

[MOD: edited code block - sh]

1 Answer

Martin Wildfeuer
PLUS
Martin Wildfeuer
Courses Plus Student 11,071 Points

Phew, it's always hard to to debug this amount of code in a text editor, but I'll give it a go. So keep in mind this is untested, don't blame me if it's not running out of the box ;) It's more the general idea behind it.

For the sake of this example let's make library a static var, that is, unlike an instance var we can call it on the class/struct directly, without having to have an instance of it (BenchmarkWODs().library vs. BenchmarkWODs.library)

// Inside BenchmarkWODs
static let library = [...]

Let's look at WODList. Although this was named WODList, it's basically a single item. It has one name, one exercise and one description. So let's use it as such. As we know that BenchmarkWODs.library is an array of dictionaries with string keys and string values [[String: String]], we will use this for initializing a single WOD item.

struct WOD {
    let name: String?
    let exercise: String?
    let description: String?

    init(dictionary: [String: String]) {
        name = dictionary["name"]
        exercise = dictionary["exercises"] 
        description = dictionary["description"]
    }
}

Now, all we have to do is initialize an array of WOD [WOD] with the data we get from the library. Firstly, let's init an empty array of WODs. For the sake of this example, let's fill it with data in viewDidLoad()

class BenchmarkWODViewController: UITableViewController {

    var wodList = [WOD]()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Let's iterate over the array of dictionaries,
        // create a WOD instance for every item and
        // add it to the wodList
        for wodData in BenchmarkWODs.library {
            let wod = WOD(dictionary: wodData)
            wodList.append(wod)
        }

        // Alternatively, you could use map
        // wodList = BenchmarkWods.library.map {
        //     return WOD(dictionary: $0)
        // }
    }
//...

Ok, now we have filled the wodListwith the data from your library. Let's display this data.

// You could leave this method out, 1 is the default anyhow
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
      return 1
}

// Return the number of WOD items in the wodList
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
     return wodList.count
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("BenchmarkCell", forIndexPath: indexPath)

    // Get the item with the index that matches our row,
    // that is indexPath.row
    let wod = wodList[indexPath.row]

    // wodName is an optional, so let's unwrap it
    if let wodName = wod.name {
        cell.textLabel?.text = wodName
    }

    return cell
}

One comment about force unwrapping with !: don't. ever. do. it. Optionals are one of the most important language features of Swift to keep your code from crashing. Force unwrapping bypasses this. There are very rare occasions where this might be used, but as a rule of thumb: don't use it.

Hope this helps :)

Well holy hell that worked!

Thanks man

If you want some more points, my search bar is returning nil. https://teamtreehouse.com/community/why-wont-this-search-bar-work