首页 > 解决方案 > 每次将应用程序推回前台时刷新 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 的最佳方式是什么?我的目标是删除这些旧警报并重新加载视图。如果一个警报在通知中心没有任何待处理的通知(意味着该通知已经被执行),则该警报被认为是旧的。

标签: iosswiftcompletionhandler

解决方案


不要在应用程序委托中放置任何代码。让视图控制器注册以在应用程序进入前台时接收通知。

将其添加到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 下运行,那么您需要注册这两个通知,但您可以使用相同的选择器。


推荐阅读