How to conditionally section data model in UITableView?

250 Views Asked by At

I have a model object being returned in JSON from Firebase.

{
    "id": 1,
    "name": "Jon Doe",
    "time": ["1525592246"]
},
{
    "id": 2,
    "name": "Jane Doe",
    "time": ["1525592266"]
},

I would like to structure these objects into sections in a UITableView based on the below:

enum DiarySectionType {
    case Today
    case Tomorrow
    case ThisWeek
    case ThisMonth
    case Later
}

I.e If a "time" is today it will be in the today section of the UITableView

What is the best way to approach this? I've thought of having separate arrays for each. But don't think that's the way to go.

As always any help appreciated.

1

There are 1 best solutions below

6
Abdelahad Darwish On

First you need helper extension for your Date

extension Date {

    public func component(_ component: Calendar.Component) -> Int {
        let calendar = Calendar.autoupdatingCurrent
        return calendar.component(component, from: self)
    }

    public var isToday: Bool {
        let calendar = Calendar.autoupdatingCurrent
        return calendar.isDateInToday(self)
    }

    public var isTomorrow: Bool {
        let calendar = Calendar.autoupdatingCurrent
        return calendar.isDateInTomorrow(self)
    }

    public var isThisWeek: Bool {
        return isInSameWeek(date: Date())
    }
    public var isThisMonth: Bool {
        return isInSameMonth(date: Date())
    }
    public var islater: Bool {
       return isInSameMonth(date: Date()) ? false : true
    }

}
extension Date {
    func isInSameWeek(date: Date) -> Bool {
        return Calendar.current.isDate(self, equalTo: date, toGranularity: .weekOfYear)
    }
    func isInSameMonth(date: Date) -> Bool {
        return Calendar.current.isDate(self, equalTo: date, toGranularity: .month)
    }
}

Then your Enum

enum DiarySectionType:Int{
    case Today
    case Tomorrow
    case ThisWeek
    case ThisMonth
    case Later
    case count // use for number of section
    init (with date:Date){

        if date.isToday {
            self = .Today
        }else if date.isTomorrow{
             self = .Tomorrow
        }else if date.isThisWeek{
            self = .ThisWeek
        }else if date.isThisMonth{
             self = .ThisMonth
        }else{
           self = .Later
        }
    }
}

Your data Formalize as you need

struct Item{
    var id : Int
    var name : String
    var time : Double
    init(id:Int, name:String,time:Double) {

        self.id = id
        self.name = name
        self.time = time
    }
}

// Controller

  class  ViewController: UIViewController{

          var data = [Item]() // your data before sections
          var dataWork = [DiarySectionType: [Item]]() // date After sections

        override func viewDidLoad() {
            super.viewDidLoad()

            self.sortData()

          }

   // When generating sorted table data we can easily use our TableSection to make look up simple and easy to read.
        func sortData() {
            dataWork[.Today] = data.filter({ DiarySectionType.init(with: Date.init(timeIntervalSince1970: $0.time))  == .Today })
            dataWork[.Tomorrow] = data.filter({ DiarySectionType.init(with: Date.init(timeIntervalSince1970: $0.time))  == .Tomorrow })
            dataWork[.ThisWeek] = data.filter({ DiarySectionType.init(with: Date.init(timeIntervalSince1970: $0.time))  == .ThisWeek })
            dataWork[.ThisMonth] = data.filter({ DiarySectionType.init(with: Date.init(timeIntervalSince1970: $0.time))  == .ThisMonth })
            dataWork[.Later] = data.filter({ DiarySectionType.init(with: Date.init(timeIntervalSince1970: $0.time))  == .Later })
        }
    }




extension ViewController: UITableViewDataSource, UITableViewDelegate {

    // As long as `count` is the last case in our TableSection enum,
    // this method will always be dynamically correct no mater how many table sections we add or remove.
    func numberOfSections(in tableView: UITableView) -> Int {
        return DiarySectionType.count.rawValue
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Using Swift's optional lookup we first check if there is a valid section of table.
        // Then we check that for the section there is data that goes with.
        if let tableSection = DiarySectionType(rawValue: section), let data = dataWork[tableSection] {
            return data.count
        }
        return 0
    }

    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        var title : String = ""
        if let tableSection = DiarySectionType(rawValue: section) {
            switch tableSection {
            case .Today:
                title = "Today"
            case .Tomorrow:
                title = "Tomorrow"
            case .ThisMonth:
                title = "ThisMonth"
            case .ThisWeek:
                title = "ThisWeek"
            case .Later:
                title = "Later"
            default:
                title = ""
            }
        }

        return title
    }


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        // Similar to above, first check if there is a valid section of table.
        // Then we check that for the section there is a row.
        if let tableSection = DiarySectionType(rawValue: indexPath.section), let item = dataWork[tableSection]?[indexPath.row] {
          // use item item

        }
        return cell
    }

}