ios - 每次将应用程序推回前台时刷新 tableView 的最有效方法是什么?
问题描述
目前我所拥有的是:
AppDelegate.applicationDidBecomeActive():
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
guard let vc = self.window?.rootViewController?.children.first as! AlarmTableViewController? else {
fatalError("Could not downcast rootViewController to type AlarmTableViewController, exiting")
}
vc.deleteOldAlarms(completionHandler: { () -> Void in
vc.tableView.reloadData()
})
}
删除旧警报():
func deleteOldAlarms(completionHandler: @escaping () -> Void) {
os_log("deleteOldAlarms() called", log: OSLog.default, type: .default)
let notificationCenter = UNUserNotificationCenter.current()
var activeNotificationUuids = [String]()
var alarmsToDelete = [AlarmMO]()
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
notificationCenter.getPendingNotificationRequests(completionHandler: { (requests) in
for request in requests {
activeNotificationUuids.append(request.identifier)
}
for alarm in self.alarms {
guard let alarmUuids = alarm.value(forKey: "notificationUuids") as! [String]? else {
os_log("Found nil when attempting to unwrap notificationUuids in deleteOldAlarms() in AlarmTableViewController.swift, cancelling",
log: OSLog.default, type: .default)
return
}
let activeNotificationUuidsSet: Set<String> = Set(activeNotificationUuids)
let alarmUuidsSet: Set<String> = Set(alarmUuids)
let union = activeNotificationUuidsSet.intersection(alarmUuidsSet)
if union.isEmpty {
alarmsToDelete.append(alarm)
}
}
os_log("Deleting %d alarms", log: OSLog.default, type: .debug, alarmsToDelete.count)
for alarmMOToDelete in alarmsToDelete {
self.removeNotifications(notificationUuids: alarmMOToDelete.notificationUuids as [String])
managedContext.delete(alarmMOToDelete)
self.alarms.removeAll { (alarmMO) -> Bool in
return alarmMOToDelete == alarmMO
}
}
completionHandler()
})
}
但感觉很恶心。另外,我现在在后台线程(执行完成处理程序的线程)上调用 tableView.reloadData() 。用户打开应用程序备份后刷新 UI 的最佳方式是什么?我的目标是删除这些旧警报并重新加载视图。如果一个警报在通知中心没有任何待处理的通知(意味着该通知已经被执行),则该警报被认为是旧的。
解决方案
不要在应用程序委托中放置任何代码。让视图控制器注册以在应用程序进入前台时接收通知。
将其添加到viewDidLoad
:
NotificationCenter.default.addObserver(self, selector: #selector(enteringForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
然后加:
@objc func enteringForeground() {
deleteOldAlarms {
DispatchQueue.main.async {
tableView.reloadData()
}
}
}
从 iOS 13 开始,您应该注册UIScene.willEnterForegroundNotification
. 如果您的应用需要在 iOS 13 和 iOS 12 下运行,那么您需要注册这两个通知,但您可以使用相同的选择器。
推荐阅读
- python - 如何修改 def __str__ 使其返回不带括号 [] 且不带“,”的矩阵
- sql - Netezza 在 SQL 中为当天的第一条记录值添加新字段
- sql - 实现 Redshift 合并/更新操作的最有效方法是什么
- objective-c - 在 Objective-c 或 Swift 中,每第 n 次循环迭代做一些事情
- python - 使用进度条停止功能不起作用
- python - 在 pandas 上使用 pivot 会引入不需要的 NaN
- javascript - 当使用 useState 中的 setState 函数作为 useEffect 中的参数时,为什么不需要编写回调
- c++ - CMake 不同存储库中的多个库
- python-3.x - 使用python连接两个CSV文件
- javascript - 创建宏计算器 - 尝试添加下拉菜单时获得 NaN 结果