Populating TableView with multiple sections and multiple dictionary in an array in Swift
If itemA array for Category A, itemB array for Category B and so on then you can return array count in numberOfRowsInSection
this way.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch (section) {
case 0:
return itemsA.count
case 1:
return itemsB.count
default:
return itemsC.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "StoreCell") as! UITableViewCell
switch (indexPath.section) {
case 0:
//Access itemsA[indexPath.row]
case 1:
//Access itemsB[indexPath.row]
default:
//Access itemsC[indexPath.row]
}
return cell
}
Note: It is batter if you create single Array of struct or custom class that will reduce all your array with single array.
Swift - Populating TableViews with multiple sections from multidimensional array
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
}
Populate different sections of tableview from single Dictionary in Swift
Group the elements that should be in the same section in array like this
var menuItems = [
[
["city":"Lahore","cityimage":"2","country":"Pakistan"],
["city":"istanbul","cityimage":"3","country":"Turkey"]
],
[
["city":"Moscow","cityimage":"4","country":"Russia"],
["city":"Riyadh","cityimage":"5","country":"KSA"]
]
]
you can access them with
cell.lblCityName.text!=menuItems[indexPath.section][indexPath.row]["city"]!
UITableView with Multiple Sections in Alphabetical Order using Realm and Swift, with multiple labels connected with same data
There are a number of issues with the code in the question and instead of trying to dissect them, let me provide an example that may help.
Suppose we have a bunch of fruits stored in Realm. We want to display those in alphabetical order in a tableview using sections
A
Apple
B
Banana
etc
This first piece of code is a structure to hold a section title and then an array of the fruits that go in that section. Also, a class fruitNameArray which will act as our tableView DataSource that holds all of the FruitStructs.
struct FruitStruct {
var sectionTitle = ""
var fruitNameArray = [String]()
}
var fruitDataSource = [FruitStruct]()
I am using an array to hold the initial data but in your case it could be a Realm results object populated from a Realm. This is called from viewDidLoad to organize our data into the dataSource array
func setupDataSourceData() {
let fruitArray = ["Apple", "Pear", "Banana", "Bing Cherry", "Grape", "Orange", "Plum", "Watermelon", "Cantelope"]
let allFirstChars = fruitArray.map { String($0.prefix(1)) } //get all first chars for section titles
let sectionTitles = Array(Set(allFirstChars)).sorted() //eliminate dups and sort
//iterate over the unique section titles and get the fruits that are in that section
// sort and then craft structs to hold the title and the associated fruits
sectionTitles.forEach { firstChar in
let results = fruitArray.filter { $0.prefix(1) == firstChar }
let sortedFruits = results.sorted()
let fruit = FruitStruct(sectionTitle: firstChar, fruitNameArray: sortedFruits)
fruitDataSource.append(fruit)
}
for fruitData in fruitDataSource {
print(fruitData.sectionTitle)
let fruits = fruitData.fruitNameArray
for fruitName in fruits {
print(" \(fruitName)")
}
}
}
Then, there are 4 functions a tableView needs to show the sections and then the rows in each section. You appear to have these 4 but an additional one sectionIndexTitles
which may not be needed.
//
//handle sections
//
func numberOfSections(in tableView: UITableView) -> Int {
return self.fruitDataSource.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let title = self.fruitDataSource[section].sectionTitle
return title
}
//
//handleTableView rows
//
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let rowsInSection = self.fruitDataSource[section].fruitNameArray.count
return rowsInSection
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellReuseIdentifier", for: indexPath)
let text = self.fruitDataSource[indexPath.section].fruitNameArray[indexPath.row]
cell.textLabel?.text = text
return cell
}
Note that I am not performing any filtering and any other stuff as the tableView is being populated. That section of code needs to be fast and lean to the UI is as responsive as possible.
I am just getting a string
let text = self.fruitDataSource[indexPath.section].fruitNameArray[indexPath.row]
but in your case, you may want to return an exersise object where you could then get the exerciseName and bodypartName to then assign those in the custom cellView
Best Practice Note: class properties should be lower cased - exerciseName, not uppercase, ExerciseName. Class and Struct names are typically capitalized.
How do I populate a tableView with all the data in a dictionary?
A tableView displays stuff in order. A dictionary isn't ordered. By looping over your dictionary with "for (key, value) in clubDict" you will only get the last entry in the dictionary to be displayed.
What you have to do is get the unordered dictionary into an ordered form like an array. For example like so:
let dict = ["key1" : "value1"]; // Your dictionary. Use the one you already have
var arr : [(String, String)] = [];
for (key, value) in dict {
arr.append((key, value));
}
Then you will have to adjust the "numberOfRowsInSection" method to now use arr.count
For each cell the cellForRowAtIndexPath method will be called.
There you extract the correct entry from the array by its index:
let (key, value) = arr[indexPath.row]; //read element for the desired cell
cell.textLabel?.text = key
cell.detailTextLabel?.text = value.address
You have to adjust the datatypes to your needs. I just took a dictionary of String:String
How do I populate two sections in a tableview with two different arrays using swift?
TableView Cells
You could use a multidimensional array. For example:
let data = [["0,0", "0,1", "0,2"], ["1,0", "1,1", "1,2"]]
For the number of sections use:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return data.count
}
Then, to specify the number of rows in each section use:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data[section].count
}
Finally, you need to setup your cells:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellText = data[indexPath.section][indexPath.row]
// Now do whatever you were going to do with the title.
}
TableView Headers
You could again use an array, but with just one dimension this time:
let headerTitles = ["Some Data 1", "KickAss"]
Now to set the titles for the sections:
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section < headerTitles.count {
return headerTitles[section]
}
return nil
}
The code above checks to see there's a title for that section and returns it, otherwise nil
is returned. There won't be a title if the number of titles in headerTitles
is smaller than the number of arrays in data
.
The Result
UITableView With Multiple Sections
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2 ;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section==0)
{
return [array1 count];
}
else{
return [array2 count];
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if(section == 0)
return @"Section 1";
else
return @"Section 2";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if (indexPath.section==0) {
ObjectData *theCellData = [array1 objectAtIndex:indexPath.row];
NSString *cellValue =theCellData.category;
cell.textLabel.text = cellValue;
}
else {
ObjectData *theCellData = [array2 objectAtIndex:indexPath.row];
NSString *cellValue =theCellData.category;
cell.textLabel.text = cellValue;
}
return cell;
}
Implement a TableView with Sections and populating it with data from a struct
Updated answer
I ran the code shared by OP and noticed that it was crashing. The main reason why it does so is because SymptomsSections
& SymptomsList
does not have same number of contents, thus resulting in the out of index range crash
for the smaller array which in our case is SymptomsList
. For workaround I have added the line SymptomsList.indices.contains(index)
which basically checks whether any object exists at the given index before accessing it. This resolved our crash. Then I proceeded to update the dictionaries and the accessing method. Also attached is the output screen for your understanding.
Please go through the code
let SymptomsSections = ["General", "Respiratory", "Cardiac", "Abdominal", "Neurological", "Psychiatrical"]
let SymptomsList = [[["name":"Dry mouth", "checked" : true], ["name":"Malaise", "checked" : false], ["name":"Asthenia", "checked" : true]],
[["name":"Dyspnoea", "checked" : true], ["name":"Wheezing", "checked" : false]],
[["name":"Orthopnoea", "checked" : false], ["name":"Angina", "checked" : true]],
[["name":"Coffee ground vomiting", "checked" : true], ["name":"Melaena", "checked" : true]],
[["name":"Agnosia", "checked" : false], ["name":"Apraxia", "checked" : true]]]
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.SymptomsSections[section]
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.SymptomsSections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if SymptomsList.indices.contains(section) {
return SymptomsList[section].count
} else {
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SymptomsCell", for: indexPath)
if SymptomsList.indices.contains(indexPath.section) {
cell.textLabel?.text = SymptomsList[indexPath.section][indexPath.row]["name"] as? String
if SymptomsList[indexPath.section][indexPath.row]["checked"] as! Bool {
cell.accessoryType = UITableViewCellAccessoryType.checkmark
} else {
cell.accessoryType = UITableViewCellAccessoryType.none
}
} else {
cell.textLabel?.text = nil
cell.accessoryType = UITableViewCellAccessoryType.none
}
return cell
}
Original answer
Well, to show something you need to know that thing. Not sure how you are getting your data. But I can imagine your datasource for tableview looks something like this:
let symptoms = ["fever", "cold", "heart ache"]
You're correct when you said that the easiest way out would be using dictionary. Imagine having the updated data source being an array of dictionaries, like so:
let symptoms = [["name":"fever", "checked":true], ["name":"cold", "checked":true], ["name":"heart ache", "checked":false]]
While assigning the cell in cellForRow
method. You can use something like below:
cell.titleLabel.text = symptoms[indexPath.row]["name"]
if symptoms[indexPath.row]["checked"] {
cell.accessoryType = UITableViewCellAccessoryType.checkmark
} else {
cell.accessoryType = UITableViewCellAccessoryType.none
}
Swift: How to configure a tableview with multiple sections dynamically using JSON data
You can build your data structure like that:
var teams = [[String: [Datum]]]()
for team in teams {
let teamProjects = projects.filter {$0.relationships.team.id == team.id}
let teamData = [team: [teamProjects]]
teams.append(teamData)
}
and in numberOfRows method:
let team = teamsWithProjects[section-1]
let teamProject = Array(team.values)[0]
return teamProject.count
and in cellForRow method:
let team = teamsWithProjects[indexPath.section-1]
let teamProject = Array(team.values)[0]
projectCell.textLabel?.text = teamProject[indexPath.row].attributes.name
Hope this will help you!
How to populate sections of an indexed UITableView with different array for sectionIndexTitles
Group the people array by the state name and create array of tuple from the dictionary. Then use that array in tableview data source methods
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
struct Person {
var name: String
var state: String
}
var allPeople = [Person]()
var groupedPeople = [(state:String, people:[Person])]()
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
allPeople = [Person(name: "a", state: "Alaska"), Person(name: "x", state: "Florida"),
Person(name: "c", state: "California")]
groupedPeople = Dictionary(grouping: allPeople, by: { $0.state }).sorted(by: { $0.key < $1.key })
.map({ (state:$0.key, people:$0.value)
})
}
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return Array(Set(groupedPeople.map({ String($0.state.first!) })))
}
func numberOfSections(in tableView: UITableView) -> Int {
return groupedPeople.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return groupedPeople[section].state
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return groupedPeople[section].people.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .subtitle, reuseIdentifier: "cell")
cell.textLabel?.text = groupedPeople[indexPath.section].people[indexPath.row].name
cell.detailTextLabel?.text = groupedPeople[indexPath.section].people[indexPath.row].state
return cell
}
}
Update
When you have more sections than sectionIndexTitles
you should implement sectionForSectionIndexTitle
method and return appropriate section index.
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
if let index = groupedPeople.firstIndex(where: { $0.state.hasPrefix(title) }) {
return index
}
return 0
}
Related Topics
Invalid Signature - Code Object Is Not Signed at All
Randomly Choosing an Item from a Swift Array Without Repeating
Using Tesseract to Recognize License Plates
How to Make a Call Which Begin with * in Iphone
Cast Value of Type 'Uitableviewcell' to Custom Cell
Repeat Interval for Unnotification
What Privacy-Violating or Device-Changing Things How to Do on an Iphone
Sending Data from One Viewcontroller to Another
How to Make a Swiftui Gesture That Keeps Running Code While the View Is Pressed
How to Force My Keyboard to Be Up on My Program's Start in Swift
How to Use Device Instead of Simulator
No Such File and Directory Found Xcode 7
How to Fetch User's Email Using Facebook
Objective-C Delay Action with Blocks
Cellforitematindexpath Not Called But Numberofitemsinsection Does
Swift 3 How to Get Date for Tomorrow and Yesterday ( Take Care Special Case ) New Month or New Year