Reputation: 143
I'm new to Swift, and I am currently creating a diary app that asks the user questions. I'm storing the user's input like this:
dict = ["date": ["question1": "answer", "question2": "answer"]]
Now I need to display this data back to the user in a tableview, where "date" is a title and "question1" is the description.
I've looked online, but answers seem to reference "indexPath.row" for inputting information into a cell, but since this is a dictionary of strings, I can't do that.
Thank you for your help!
Upvotes: 3
Views: 1974
Reputation: 642
You can use the dictionary as it is without changing
You should sort before use, remember
let dict = ["date": ["question1": "answer", "question2": "answer"]]
Number of sections
override func numberOfSections(in tableView: UITableView) -> Int {
return dict.count
}
Title of the header
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return Array(dict)[section].key
}
Number of rows in section
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let key = Array(dict)[section].key
return dict[key]?.count ?? 0
}
Cell for row at
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let key = Array(dict)[section].key
if let questionsDict = dict[key] {
let keyValue = Array(questionsDict)[indexPath.row]
print("Question: \(keyValue.key), Answer: \(keyValue.value)")
}
return cell
}
Upvotes: 1
Reputation: 53121
Rather than using an array of dictionaries, you should consider using objects that better represent your data.
struct Question: {
let question: String
let answer: String
}
struct DiaryDay {
let date: Date // Note this is a Date object, not a String
let questions: [Question]
}
then you have
let diaryDays = DiaryDay(date: <date>, questions:
[Question(question: "question1": answer: "answer"),
Question(question: "question2": answer: "answer")])
while there's a bit more code, going forward you'll find it easier to see what's happening.
It looks like you should have a section per diary day…
override func numberOfSections(in tableView: UITableView) -> Int {
return diaryDays.count
}
and then one row per question…
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let diaryDay = diaryDays[section]
return diaryDay.questions.count
}
and then configure your cell…
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// dequeue cell
let diaryDay = diaryDays[indexPath.section]
let question = diaryDay.questions[indexPath.row]
cell.question = question
return cell
}
and show the date in the section header…
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let diaryDay = diaryDays[section]
return // formatted diaryDay.date
}
Upvotes: 5
Reputation: 1015
you will have to do a little preparation before you can display data from the dictionary type you are using. Also remember the dictionary is not order list so which order the data will be printed solely depends on system. One approach would be the following
var data = ["date1":["q1":"A1","q2":"A2","q3":"A3"],"date2":["q1":"A1","q2":"A2","q3":"A3"]] . //This is data from your example
var displayableData = [(title: String, qAndA: [(question: String, answer: String)])]() //this is what we will be needing
override func viewDidLoad() {
super.viewDidLoad()
//convert the whole dictionary to tuple
displayableData = data.map { ($0.key, $0.value.map{ ($0.key, $0.value)})}
//here we have converted the dictionary to what we need
}
override func numberOfSections(in tableView: UITableView) -> Int {
return displayableData.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return displayableData[section].qAndA.count
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 55.0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let currentQA = displayableData[indexPath.section].qAndA[indexPath.row]
cell.textLabel?.text = "\(currentQA.question) -> \(currentQA.answer)"
return cell
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 30.0
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 30.0))
view.backgroundColor = UIColor.lightGray
let label = UILabel(frame: CGRect(x: 10, y: 0, width: view.bounds.width - 20, height: 30.0))
label.text = displayableData[section].title
view.addSubview(label)
return view
}
Upvotes: 2
Reputation: 3314
You can try out using map
. here Dictionary
converts into Array of Dictionary.
let dict = ["date": ["question1": "answer", "question2": "answer"]]
if let value = dict["date"] {
let v = value.map {
["question": $0.key, "answer": $0.value]
}
debugPrint(v)
}
Upvotes: 0