You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现提醒触发后实时自动更新FirstVC中UITableViewCell的提醒图标状态

解决提醒触发后实时移除FirstVC中Cell图标问题

首先,你目前通过进入SecondVC时比较时间的方式属于被动更新,要实现实时移除图标,核心是在通知触发的那一刻就同步更新数据模型并通知FirstVC刷新UI。下面是具体的实现步骤:

1. 监听通知触发事件

当系统触发你的提醒通知时,不管App是在前台还是后台,我们都能通过UNUserNotificationCenter的代理方法捕获这个事件。

步骤1:设置通知中心代理

在AppDelegate或者SceneDelegate中(根据你的iOS版本),先设置代理并请求通知权限:

import UserNotifications

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    UNUserNotificationCenter.current().delegate = self
    // 请求通知权限
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
        if granted {
            print("通知权限已获取")
        }
    }
    return true
}

步骤2:处理通知触发回调

实现UNUserNotificationCenterDelegate的两个关键方法,分别处理前台和后台/锁屏状态下的通知:

extension AppDelegate: UNUserNotificationCenterDelegate {
    // App在前台时收到通知的处理
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        handleTriggeredReminder(notification: notification)
        // 可以选择显示通知弹窗
        completionHandler([.banner, .sound])
    }
    
    // 用户点击通知后的处理(后台/锁屏状态)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        handleTriggeredReminder(notification: response.notification)
        completionHandler()
    }
    
    // 统一处理提醒触发的逻辑
    private func handleTriggeredReminder(notification: UNNotification) {
        // 从通知的userInfo中获取任务ID(设置提醒时要把任务ID存进去)
        guard let taskId = notification.request.content.userInfo["taskId"] as? String else { return }
        
        // 1. 更新你的数据模型:找到对应任务,标记提醒已触发
        // 假设你用Core Data存储任务,这里示例简化处理
        if let task = yourTaskStorage.getTask(withId: taskId) {
            task.hasActiveReminder = false
            yourTaskStorage.saveContext()
        }
        
        // 2. 发送自定义通知,告诉FirstVC需要刷新UI
        NotificationCenter.default.post(name: NSNotification.Name("ReminderTriggered"), object: taskId)
    }
}

2. 在FirstVC中监听自定义通知并刷新UI

在FirstVC中,我们需要监听上面发送的自定义通知,收到后找到对应的Cell并移除图标:

class FirstVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
    var tasks: [Task] = []
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 注册自定义通知监听
        NotificationCenter.default.addObserver(self, selector: #selector(handleReminderTriggered(_:)), name: NSNotification.Name("ReminderTriggered"), object: nil)
    }
    
    deinit {
        // 移除监听,避免内存泄漏
        NotificationCenter.default.removeObserver(self)
    }
    
    @objc private func handleReminderTriggered(_ notification: Notification) {
        guard let taskId = notification.object as? String else { return }
        
        // 找到对应任务在数组中的索引
        if let index = tasks.firstIndex(where: { $0.id == taskId }) {
            // 更新本地数组
            tasks[index].hasActiveReminder = false
            // 刷新对应的Cell
            tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .automatic)
        }
    }
    
    // UITableViewDataSource方法中,根据hasActiveReminder判断是否显示图标
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as! TaskCell
        let task = tasks[indexPath.row]
        cell.iconImageView.isHidden = !task.hasActiveReminder
        // 其他Cell配置...
        return cell
    }
}

3. 设置提醒时记得传入任务ID

在SecondVC设置提醒的时候,一定要把任务的唯一ID存入通知的userInfo,这样触发时才能定位到对应的任务:

func setReminder(for task: Task, date: Date) {
    let content = UNMutableNotificationContent()
    content.title = "任务提醒"
    content.body = task.title
    // 存入任务ID
    content.userInfo["taskId"] = task.id
    
    let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: date)
    let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
    
    let request = UNNotificationRequest(identifier: task.id, content: content, trigger: trigger)
    UNUserNotificationCenter.current().add(request) { error in
        if let error = error {
            print("设置提醒失败:\(error)")
        } else {
            // 更新任务的提醒状态
            task.hasActiveReminder = true
            yourTaskStorage.saveContext()
        }
    }
}

额外注意点

  • 如果App被杀死状态下触发通知,用户点击通知打开App时,didReceive response方法会被调用,同样能触发更新逻辑
  • 确保你的数据存储(Core Data/UserDefaults等)是线程安全的,避免更新时出现问题
  • 自定义通知的名称建议用全局常量,避免拼写错误

内容的提问来源于stack exchange,提问作者Osama Naeem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:38:38