MateGreat
MateGreat

Reputation: 107

Sorting most descending date at top TableView

Situation

I have a tableview with scheduled local notifications stored in cells, containing a title, date, UUID and mood. They repeat weekly from the day the users chooses and works perfectly fine. I have successfully sorted the cells so that the most descending (soonest) notification is at the top of the table view through this line of code in the refreshList():

dqItems.sort(by: {$0.date < $1.date})

Problem

However, when a notification has been fired and is overdue, 7 days is being added to its date through the if (dqItem.isOverdue) function. This works - 7 days is added to the date. But the tableview doesn't re-sort the cells - the notification cell which has been rescheduled with 7 days is still at the top! Despite the fact that there are other notifications with more descending dates scheduled. (See image for example)

This is extremely frustrating and I can't managed to find a solution. Here comes a snippet from the Table View Controller file.

//Outlets
var dqItems: [DQItem] = []
var MoodString = String()

 override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    refreshList()
}

func refreshList() {

    dqItems = DQList.sharedInstance.allItems()

        dqItems.sort(by: {$0.date < $1.date})

    tableView.reloadData()
}

override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return dqItems.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "dqCell", for: indexPath) // retrieve the prototype cell (subtitle style)
    var dqItem = dqItems[(indexPath as NSIndexPath).row] as DQItem
    cell.textLabel?.text = dqItem.title as String!

    if (dqItem.isOverdue)
    { // the current time is later than the to-do item's date

        let newDate = Calendar.current.date(byAdding: .day, value: 7, to: dqItem.date)!
        dqItem.date = newDate
        dateFormatter.dateFormat = "EEEE's' 'at' HH:mm"
        print("newdate", newDate) //seven days is added!
        print("dqItem.d", dqItem.date) //same here

       viewDidAppear(true) //reload the view to re-sort the cells??? = not working

    }

    cell.detailTextLabel?.text = dateFormatter.string(from: dqItem.date as Date)

    return cell
}//End of cellforrowatindexPath

The DQItem, where the struct is.

 import UIKit

 struct DQItem {

  var title: String
  var date: Date
  var UUID: String
  var mood: String

init(date: Date, title: String, UUID: String, mood: String) { 

    self.date = date
    self.title = title
    self.UUID = UUID
    self.mood = mood

}

 //Overdue function
 var isOverdue: Bool {

     return (Date().compare(self.date) == .orderedDescending) // date is earlier than current date
}



}

Appreciate all help trying to solve this silly problem!

Example: "Today" comes after "Next Thursday" despite the fact it's more  descending

Upvotes: 0

Views: 989

Answers (1)

Phillip Mills
Phillip Mills

Reputation: 31016

Don't call viewDidAppear. That method is supposed to only be called by the UIKit. Just call your own refresh code instead.

(Even if calling view state methods was a good idea, you would be calling the wrong one since you implemented viewWillAppear to do your initial refresh.)

EDIT: For the problem of how to change your table ordering while the table is being updated, you need to wait until the current update is finished. One way to do that would be to submit the next reload request to the main queue. Since the main queue is serial, that would delay it until current work finishes.

Try moving the table reordering into its own method...

func orderTable() {
    dqItems.sort(by: {$0.date < $1.date})
    tableView.reloadData()
}

...then call it via GCD instead of calling the view lifecycle method.

DispatchQueue.main.async {
    orderTable()
}

That's the simple version. If you want to be more efficient, you can look into ways to make sure the orderTable call only happens once per reload.

Upvotes: 2

Related Questions