2

I am a beginner in Swift and have managed to understand at least the very basics of how to populate a UITableView. I am stuck now at populating multiple sections with data provided out of a dictionary.

I have a multidimensional Dictionary that assigns Objects to Categories:

var categoryDict:[String:[AnyObject]] = ["Category A": ["Object 1","Object 2"], "Category B":["Object 3"]]

Now I want to populate my TableView, so that it shows something like this:

  • Category A

    • Object 1
    • Object 2
  • Category B

    • Object 3

So far I am able to create an array of categories to return the number of sections as well as to count the arrays stored in the dictionary to get the number of rows in each specific category. Now I am completely stuck at populating the TableView with sections and rows. How can I do this? Thank you very much!

My code so far:

var categoryList:[String] = [String]()
var categoryDict:[String:[AnyObject]] = ["Category A": ["Object 1","Object 2"], "Category B":["Object 3"]]


func getLists() {
    categoryList = Array(categoryDict.keys)
    categoryList.sortInPlace(before)
}

// Sort Array
func before(value1: String, value2: String) -> Bool {
    return value1 < value2;
}

func getNumberOfEntrysInSection (Section: Int) -> Int {

    let category:String = categoryList[Section]    //Get Category for Index in CategoryList

    let value:[AnyObject] = categoryDict[category]! //Get Value for this specific Category

    let number = value.count

    return number
}


// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    getLists()
    return categoryList.count
}


override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return getNumberOfEntrysInSection(section)
}


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


override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("BufferCell", forIndexPath: indexPath)

    ???
    return cell
}
3
  • Did you set your delegate and datasource? Commented Mar 20, 2016 at 12:00
  • I think you are on right track. What is your problem bro? Commented Mar 20, 2016 at 12:04
  • I think delegate and datasource are set right - I am able to populate a table with just one section, but multiple sections are the problem: I cant find a way to say "Let the title for section 0 be the String in categoryList at a specific index, then populate the cells within that section with the values provided in categoryDict for that specific category". Do you know what I mean? All the tutorials that I've read seem to do that in a different way (that I dont really understand), but there has to be a way to put in the data as I am providing it out of the category-dictionary? Commented Mar 20, 2016 at 13:08

1 Answer 1

2

First off: A dictionary is a poor choice for storing table view contents. Dictionaries are inherently unordered, so you have to keep sorting the keys. If your data gets beyond a small number of items that sort process will take appreciable time.

If you are going to use a dictionary anyway you should refactor your code so that you keep the sorted keys and use them over and over unless the dictionary changes. I would make it so that you add a setter method to the dictionary and always use that setter to change the dictionary. The setter method would regenerate the sorted keys. That way you only have to sort the keys if the dictionary changes. (But better to get rid of the dictionary entirely.)

I would suggest creating a Section object that contains a sectionTitle String and a sectionEntries Array. Then make the table view data an array of Section objects.

However, since you have a dictionary, I'll show you how to make that code work.

You need help with your cellForRowAtIndexPath method. You are almost there. You just need to fetch the appropriate entry in your data structure using the indexPath section and row. Something like this:

override func tableView(tableView: UITableView, 
  cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
{

    let cell = tableView.dequeueReusableCellWithIdentifier("BufferCell",
     forIndexPath: indexPath)
    let section = indexPath.section 
    let row = indexPath.row

    let categoryKey:String = categoryList[section]   
    let aCategoryEntry:[String] = categoryDict[categoryKey] as! [String]
    let anObject = aCategoryEntry[row] //
    let cell.textLabel.text = anObject
    return cell
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thats exactly what I was looking for - thank you very much!! The reason I use dictionaries to store the data is simply that - for now - I somewhat understand what I am doing when using them. Efficiency and data-storage are the next step on my learning-swift-to-do-list, but for now I am happy that I can store my data at all. So again: thanks!
If you wrote the code you posted in your original question yourself then you are 90% of the way there. You just lost the "big picture" before you could go the final step.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.