在 table 视图控制器中列出计划的通知
Listing scheduled notifications in a table view controller
我试图列出用户在我的应用程序中创建和安排的所有通知,类似于苹果 'Clock' 应用程序中的警报列表。但是,每次我收到一系列通知并尝试显示它们时,它们始终无法正确显示。
每个通知每天都在同一时间重复,所以我使用 UNUserNotificationCenter.current().getPendingNotificationRequests
来获取一组通知。使用这个通知数组,我遍历每个通知,创建一个新的自定义 'Reminder' 对象并将其添加到我在 table 视图中显示通知时使用的 'Reminders' 数组控制器。
我每次使用 viewWillAppear 函数时都这样做。
代码如下:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
generateReminders()
tableView.reloadData()
}
func generateReminders()
{
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
for item in notifications {
if let trigger = item.trigger as? UNCalendarNotificationTrigger,
let triggerDate = trigger.nextTriggerDate() {
var withSound = true
if(item.content.sound != UNNotificationSound.default)
{
withSound = false
}
self.reminders.append(Reminder(identifier: item.identifier, time: triggerDate, message: item.content.body, withSound: withSound, isAPendingNotification: true))
}
}
self.remindersCount = notifications.count
}
}
当单元格即将显示在table视图控制器中时,我使用'Reminder'数组自定义每个单元格以显示通知的信息。这一切都在 'cellForRowAt' 函数中完成,代码如下。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Reminder", for: indexPath)
var text = ""
var detailText = ""
if(indexPath.row < remindersCount) {
let reminder = reminders[indexPath.row]
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm"
text = formatter.string(from: reminder.Time)
detailText = reminder.Message
}
cell.textLabel?.text = text
cell.detailTextLabel?.text = detailText
return cell
}
当用户选择另一个选项卡进行查看时,我将 'reminders' 对象重置为空,以便当他们 return 到此选项卡时,会显示更新的通知数组,代码如下。
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
reminders = [Reminder]()
remindersCount = 0
tableView.setNeedsDisplay()
}
我面临的问题是这非常不一致,有时会显示所有通知,有时只显示部分通知,有时会显示 none 个通知。但是,每次我在 UNUserNotificationCenter.current().getPendingNotificationRequests
方法中打印出通知数量时,它总是正确的数字。此外,每当我点击一个应该包含通知信息的单元格时,信息就在那里,只是没有显示。
这是这些问题的简短视频。
我不确定如何解决这个问题,我已尝试 运行 主队列和全局队列上的代码,并将服务质量设置为“.userInteractive”,如下所示,但是,仍然没有骰子。
let center = UNUserNotificationCenter.current()
let dq = DispatchQueue.global(qos: .userInteractive)
dq.async {
center.getPendingNotificationRequests { (notifications) in
for item in notifications {
if let trigger = item.trigger as? UNCalendarNotificationTrigger,
let triggerDate = trigger.nextTriggerDate() {
var withSound = true
if(item.content.sound != UNNotificationSound.default)
{
withSound = false
}
self.reminders.append(Reminder(identifier: item.identifier, time: triggerDate, message: item.content.body, withSound: withSound, isAPendingNotification: true))
}
}
self.remindersCount = notifications.count
}
}
可以从此 Github 存储库下载发生此问题的小应用程序。
https://github.com/AlexMarchant98/LitstingNotificationsIssue
您的代码的问题在于执行 tableView.reloadData()
的时间。
UNUserNotificationCenter.current().getPendingNotificationRequests()
是异步调用,因此 reminders
数组在 tableView.reloadData()
被调用后 被填充。
将 tableView.reloadData()
移动到 getPendingNotificationRequests()
的回调块的末尾应该可以解决您的问题。 (不要忘记从主线程触发 reloadData()
)
func generateReminders()
{
let center = UNUserNotificationCenter.current()
let dq = DispatchQueue.global(qos: .userInteractive)
dq.async {
center.getPendingNotificationRequests { (notifications) in
for item in notifications {
if let trigger = item.trigger as? UNCalendarNotificationTrigger,
let triggerDate = trigger.nextTriggerDate() {
var withSound = true
if(item.content.sound != UNNotificationSound.default)
{
withSound = false
}
self.reminders.append(Reminder(identifier: item.identifier, time: triggerDate, message: item.content.body, withSound: withSound, isAPendingNotification: true))
}
}
self.remindersCount = notifications.count
DispatchQueue.main.async {
self.tableView.reloadData() // <---------
}
}
}
}
您的 tableview
代码中存在一些问题,如下所列。
- 您在表格视图中使用了静态单元格,如果您有动态行,这不是正确的方法。
建议:为您的tableview
.
使用动态原型单元
remindersCount
根本不需要,因为它已经存在于您的数组中。
建议 : 使用 self.reminders.count
作为数组计数。
unwindToRemindersTableViewController()
方法有 generateReminders()
调用,这不是必需的,因为 viewWillAppear()
将在视图关闭时调用。
建议 : 检查ViewController生命周期你会正确地知道如何重新加载数据。
我已经更新了您示例项目中的一些代码。
请查找更新后的代码 here。
希望这会有所帮助!
我试图列出用户在我的应用程序中创建和安排的所有通知,类似于苹果 'Clock' 应用程序中的警报列表。但是,每次我收到一系列通知并尝试显示它们时,它们始终无法正确显示。
每个通知每天都在同一时间重复,所以我使用 UNUserNotificationCenter.current().getPendingNotificationRequests
来获取一组通知。使用这个通知数组,我遍历每个通知,创建一个新的自定义 'Reminder' 对象并将其添加到我在 table 视图中显示通知时使用的 'Reminders' 数组控制器。
我每次使用 viewWillAppear 函数时都这样做。
代码如下:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
generateReminders()
tableView.reloadData()
}
func generateReminders()
{
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests { (notifications) in
for item in notifications {
if let trigger = item.trigger as? UNCalendarNotificationTrigger,
let triggerDate = trigger.nextTriggerDate() {
var withSound = true
if(item.content.sound != UNNotificationSound.default)
{
withSound = false
}
self.reminders.append(Reminder(identifier: item.identifier, time: triggerDate, message: item.content.body, withSound: withSound, isAPendingNotification: true))
}
}
self.remindersCount = notifications.count
}
}
当单元格即将显示在table视图控制器中时,我使用'Reminder'数组自定义每个单元格以显示通知的信息。这一切都在 'cellForRowAt' 函数中完成,代码如下。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Reminder", for: indexPath)
var text = ""
var detailText = ""
if(indexPath.row < remindersCount) {
let reminder = reminders[indexPath.row]
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm"
text = formatter.string(from: reminder.Time)
detailText = reminder.Message
}
cell.textLabel?.text = text
cell.detailTextLabel?.text = detailText
return cell
}
当用户选择另一个选项卡进行查看时,我将 'reminders' 对象重置为空,以便当他们 return 到此选项卡时,会显示更新的通知数组,代码如下。
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
reminders = [Reminder]()
remindersCount = 0
tableView.setNeedsDisplay()
}
我面临的问题是这非常不一致,有时会显示所有通知,有时只显示部分通知,有时会显示 none 个通知。但是,每次我在 UNUserNotificationCenter.current().getPendingNotificationRequests
方法中打印出通知数量时,它总是正确的数字。此外,每当我点击一个应该包含通知信息的单元格时,信息就在那里,只是没有显示。
这是这些问题的简短视频。
我不确定如何解决这个问题,我已尝试 运行 主队列和全局队列上的代码,并将服务质量设置为“.userInteractive”,如下所示,但是,仍然没有骰子。
let center = UNUserNotificationCenter.current()
let dq = DispatchQueue.global(qos: .userInteractive)
dq.async {
center.getPendingNotificationRequests { (notifications) in
for item in notifications {
if let trigger = item.trigger as? UNCalendarNotificationTrigger,
let triggerDate = trigger.nextTriggerDate() {
var withSound = true
if(item.content.sound != UNNotificationSound.default)
{
withSound = false
}
self.reminders.append(Reminder(identifier: item.identifier, time: triggerDate, message: item.content.body, withSound: withSound, isAPendingNotification: true))
}
}
self.remindersCount = notifications.count
}
}
可以从此 Github 存储库下载发生此问题的小应用程序。
https://github.com/AlexMarchant98/LitstingNotificationsIssue
您的代码的问题在于执行 tableView.reloadData()
的时间。
UNUserNotificationCenter.current().getPendingNotificationRequests()
是异步调用,因此 reminders
数组在 tableView.reloadData()
被调用后 被填充。
将 tableView.reloadData()
移动到 getPendingNotificationRequests()
的回调块的末尾应该可以解决您的问题。 (不要忘记从主线程触发 reloadData()
)
func generateReminders()
{
let center = UNUserNotificationCenter.current()
let dq = DispatchQueue.global(qos: .userInteractive)
dq.async {
center.getPendingNotificationRequests { (notifications) in
for item in notifications {
if let trigger = item.trigger as? UNCalendarNotificationTrigger,
let triggerDate = trigger.nextTriggerDate() {
var withSound = true
if(item.content.sound != UNNotificationSound.default)
{
withSound = false
}
self.reminders.append(Reminder(identifier: item.identifier, time: triggerDate, message: item.content.body, withSound: withSound, isAPendingNotification: true))
}
}
self.remindersCount = notifications.count
DispatchQueue.main.async {
self.tableView.reloadData() // <---------
}
}
}
}
您的 tableview
代码中存在一些问题,如下所列。
- 您在表格视图中使用了静态单元格,如果您有动态行,这不是正确的方法。
建议:为您的tableview
.
remindersCount
根本不需要,因为它已经存在于您的数组中。
建议 : 使用 self.reminders.count
作为数组计数。
unwindToRemindersTableViewController()
方法有generateReminders()
调用,这不是必需的,因为viewWillAppear()
将在视图关闭时调用。
建议 : 检查ViewController生命周期你会正确地知道如何重新加载数据。
我已经更新了您示例项目中的一些代码。
请查找更新后的代码 here。
希望这会有所帮助!