What you need to do is group the data by date
let grouped: [Data: [Objects]]!
//...
self.result = Array(self.data)
grouped = Dictionary(grouping: result) { (element) -> Date in
return element.date
}
This will produce a dictionary grouping all the elements with the same Date
. Now, you might need to do some additional decision making, for example, grouping them only by month and year instead.
Once you have this, you basically have the structure of your table (sections are the dictionary keys and the rows data behind the keys.
For convince, I might also include...
sections = grouped.keys.sorted()
to make it faster to access the keys in a specified order.
Then you just need to apply the appropriate data to your delegate...
func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
// Set the spacing between sections
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return cellSpacingHeight
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return grouped[sections[section]]!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let rows = grouped[sections[indexPath.section]]!
let row = rows[indexPath.row]
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE - dd.MM.yyyy"
let stringGivenDate = dateFormatter.string(from: row.date!)
cell.textLabel?.text = "\(stringGivenDate)"
cell.detailTextLabel?.text = "\(row.name!)"
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let date = sections[section]
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE - dd.MM.yyyy"
return dateFormatter.string(from: date)
}
As a side note, DateFormatter
is expensive, so you might consider making this a instance property instead
Runnable example....

//
// ViewController.swift
// QuickTest
//
// Created by Shane Whitehead on 10/2/19.
// Copyright © 2019 Swann Communications. All rights reserved.
//
import UIKit
struct Stuff: CustomDebugStringConvertible {
let date: Date
let name: String
var debugDescription: String {
return "\(date) = \(name)"
}
}
extension Date {
static func random(daysBack: Int)-> Date {
let day = arc4random_uniform(UInt32(daysBack))+1
let hour = arc4random_uniform(23)
let minute = arc4random_uniform(59)
let today = Date(timeIntervalSinceNow: 0)
let calendar = Calendar.current
var offsetComponents = DateComponents()
offsetComponents.day = -Int(day)
offsetComponents.hour = Int(hour)
offsetComponents.minute = Int(minute)
let randomDate = calendar.date(byAdding: offsetComponents, to: today)
return randomDate!
}
var startOfDay: Date {
let calendar = Calendar.current
return calendar.startOfDay(for: self)
}
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
let cellSpacingHeight: CGFloat = 5
var grouped: [Date: [Stuff]] = [:]
var sections: [Date] = []
var headerDateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM yyyy"
return dateFormatter
}()
var cellDateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE - dd.MM.yyyy"
return dateFormatter
}()
override func viewDidLoad() {
super.viewDidLoad()
retreiveData()
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = UITableView.automaticDimension
tableView.sectionHeaderHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 44
tableView.estimatedSectionHeaderHeight = 44
tableView.reloadData()
}
func retreiveData() {
var data: [Stuff] = []
for index in 0..<100 {
let stuff = Stuff(date: Date.random(daysBack: 10), name: "\(index)")
data.append(stuff)
}
grouped = Dictionary(grouping: data) { (element) -> Date in
return element.date.startOfDay
}
sections = grouped.keys.sorted()
}
// MARK: - Table View delegate methods
func numberOfSections(in tableView: UITableView) -> Int {
return grouped.count
}
// Set the spacing between sections
// func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
// return cellSpacingHeight
// }
/*func numberOfSections(in tableView: UITableView) -> Int {
return 1
}*/
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return grouped[sections[section]]!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let rows = grouped[sections[indexPath.section]]!
let row = rows[indexPath.row]
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE - dd.MM.yyyy"
let stringGivenDate = dateFormatter.string(from: row.date)
cell.textLabel?.text = "\(stringGivenDate)"
cell.detailTextLabel?.text = "\(row.name)"
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let date = sections[section]
return headerDateFormatter.string(from: date)
}
}