Reputation: 107
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!
Upvotes: 0
Views: 989
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