每次将应用程序推回前台时刷新 tableView 的最有效方法是啥?
Posted
技术标签:
【中文标题】每次将应用程序推回前台时刷新 tableView 的最有效方法是啥?【英文标题】:What's the most efficient way to refresh a tableView every time the app is pushed back to the foreground?每次将应用程序推回前台时刷新 tableView 的最有效方法是什么? 【发布时间】:2018-12-02 23:30:12 【问题描述】:目前我拥有的是这样的:
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()
)
deleteOldAlarms():
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 的最佳方式是什么?我的目标是删除这些旧警报并重新加载视图。如果一个警报在通知中心没有任何待处理的通知(意味着该通知已经被执行),则该警报被认为是旧的。
【问题讨论】:
你可以在 NSNotificationCenter 中使用通知吗? 使用通知做什么,更新视图?我假设您是说使用通知来触发应用程序中发生的事情,对吗?我怎么做?另外,不是只有当用户点击通知时才会触发该操作吗? 您的问题是什么?deleteOldAlarms
的实现还是需要从app delegate中调用?
view controller 与 deleteOldAlarms 无关,如我所见。所以最好用 alarmmanager 类管理警报,并在 viewdidload 中重新刷新 tableView。
考虑到我需要在 deleteOldAlarms() 中调用 notificationCenter.getPendingNotificationRequests(),并且每次都需要调用 deleteOldAlarms(),我更想知道应该使用什么模式来刷新视图该应用程序进入前台。如果我调用 deleteOldAlarms(),我是否保留了用于刷新视图的 completionHandler 模式,因为在 getPendingNotificationRequests() 方法完成之前不需要刷新视图?
【参考方案1】:
不要在应用委托中放置任何代码。让视图控制器注册以在应用进入前台时接收通知。
将此添加到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 下运行,那么您需要注册这两个通知,但您可以使用相同的选择器。
【讨论】:
DispatchQueue.main.asyc
有什么作用,我为什么要使用它?
确保在主队列上调用reloadData
。
那么您认为我应该在 deleteOldAlarms() 中使用 completionHandler 模式,还是在 getPendingNotificationRequests() 方法完成后有其他更好的方法来刷新视图?
绝对保留完成处理程序。这使得deleteOldAlarms
更加通用。它所做的只是删除旧警报并更新数据模型。让完成处理程序决定完成后要做什么(例如重新加载表格视图)。【参考方案2】:
您可以使用NSNotification
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
在didBecomeActive
中调用tableView.reloadData()
,应该就是这样了。您应该记得在deinit
中取消注册观察者。
NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil)
【讨论】:
以上是关于每次将应用程序推回前台时刷新 tableView 的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章