【问题标题】:Delete a particular local notification删除特定的本地通知
【发布时间】:2011-09-14 12:03:14
【问题描述】:

我正在开发一个基于本地通知的 iPhone 警报应用程序。

删除警报时,应取消相关的本地通知。但是如何确定要取消本地通知数组中的哪个对象呢?

我知道[[UIApplication sharedApplication] cancelLocalNotification:notification] 方法,但我怎样才能得到这个“通知”来取消它?

【问题讨论】:

    标签: objective-c iphone uilocalnotification usernotifications


    【解决方案1】:

    Swift 4 解决方案:

    UNUserNotificationCenter.current().getPendingNotificationRequests { (requests) in
      for request in requests {
        if request.identifier == "identifier" {
          UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: ["identifier"])
        }
      }
    }   
    

    【讨论】:

      【解决方案2】:

      swift 3 样式:

      final private func cancelLocalNotificationsIfIOS9(){
      
      
      //UIApplication.shared.cancelAllLocalNotifications()
      let app = UIApplication.shared
      guard let notifs = app.scheduledLocalNotifications else{
          return
      }
      
      for oneEvent in notifs {
          let notification = oneEvent as UILocalNotification
          if let userInfoCurrent = notification.userInfo as? [String:AnyObject], let uid = userInfoCurrent["uid"] as? String{
              if uid == uidtodelete {
                  //Cancelling local notification
                  app.cancelLocalNotification(notification)
                  break;
              }
          }
      }
      

      }

      iOS 10 使用:

          let center = UNUserNotificationCenter.current()
          center.removePendingNotificationRequests(withIdentifiers: [uidtodelete])
      

      【讨论】:

        【解决方案3】:

        iMOBDEV 的solution 可以完美地删除特定通知(例如,在删除警报之后),但当您需要选择性地删除任何已经触发且仍在通知中心的通知时,它特别有用。

        可能的情况是:警报通知触发,但用户打开应用程序时未点击该通知并再次安排该警报。 如果您想确保给定项目/警报的通知中心只能显示一个通知,这是一个好方法。它还允许您不必在每次打开应用程序时清除所有通知,这是否更适合应用程序。

        • 在创建本地通知时,使用NSKeyedArchiver 将其存储为DataUserDefaults 中。您可以创建一个与您在通知的 userInfo 字典中保存的内容相同的密钥。如果它与 Core Data 对象相关联,您可以使用其唯一的 objectID 属性。
        • 使用NSKeyedUnarchiver 检索它。现在您可以使用 cancelLocalNotification 方法将其删除。
        • 相应地更新UserDefaults 上的密钥。

        这是该解决方案的 Swift 3.1 版本(适用于 iOS 10 以下的目标):

        商店

        // localNotification is the UILocalNotification you've just set up
        UIApplication.shared.scheduleLocalNotification(localNotification)
        let notificationData = NSKeyedArchiver.archivedData(withRootObject: localNotification)
        UserDefaults.standard.set(notificationData, forKey: "someKeyChosenByYou")
        

        检索和删除

        let userDefaults = UserDefaults.standard
        if let existingNotificationData = userDefaults.object(forKey: "someKeyChosenByYou") as? Data,
            let existingNotification = NSKeyedUnarchiver.unarchiveObject(with: existingNotificationData) as? UILocalNotification {
        
            // Cancel notification if scheduled, delete it from notification center if already delivered    
            UIApplication.shared.cancelLocalNotification(existingNotification)
        
            // Clean up
            userDefaults.removeObject(forKey: "someKeyChosenByYou")
        }
        

        【讨论】:

        • 为我工作。所有其他建议都没有,因为数组是空的。
        • 对 iOS 10 有任何想法吗?
        • @Danpe:在此处查看“管理传递的通知”部分:developer.apple.com/reference/usernotifications/…
        • 使用 swift 3 和 Xcode 处理的小模组为我工作。
        • @beshio :感谢您的提醒。我已经更新了它的语法。
        【解决方案4】:

        您可以在本地通知的用户信息中保存唯一的键值。 获取所有本地通知,遍历数组并删除特定通知。

        代码如下,

        OBJ-C:

        UIApplication *app = [UIApplication sharedApplication];
        NSArray *eventArray = [app scheduledLocalNotifications];
        for (int i=0; i<[eventArray count]; i++)
        {
            UILocalNotification* oneEvent = [eventArray objectAtIndex:i];
            NSDictionary *userInfoCurrent = oneEvent.userInfo;
            NSString *uid=[NSString stringWithFormat:@"%@",[userInfoCurrent valueForKey:@"uid"]];
            if ([uid isEqualToString:uidtodelete])
            {
                //Cancelling local notification
                [app cancelLocalNotification:oneEvent];
                break;
            }
        }
        

        SWIFT:

        var app:UIApplication = UIApplication.sharedApplication()
        for oneEvent in app.scheduledLocalNotifications {
            var notification = oneEvent as UILocalNotification
            let userInfoCurrent = notification.userInfo! as [String:AnyObject]
            let uid = userInfoCurrent["uid"]! as String
            if uid == uidtodelete {
                //Cancelling local notification
                app.cancelLocalNotification(notification)
                break;
            }
        }
        

        用户通知:

        如果您使用UserNotification (iOS 10+),请按照以下步骤操作:

        1. 在创建 UserNotification 内容时,添加唯一的identifier

        2. 使用removePendingNotificationRequests(withIdentifiers:)删除特定的待处理通知

        3. 使用removeDeliveredNotifications(withIdentifiers:)删除特定的已发送通知

        欲了解更多信息,UNUserNotificationCenter

        【讨论】:

        • @kingofBliss,你能告诉我在“uidtodelete”那里给吗?因为在我的情况下它是未声明的。
        • @ishhh 它只是一个字符串值.. 你应该声明它并用要删除的 uid 值初始化它
        • @kingofBliss,uid 在 NSLog 中总是显示为空。不知道如何摆脱这个。请帮助我
        • @ishhh 创建本地通知时,您是否在 userinfo 字典中存储了任何 uid 值?我想你错过了。
        • @kingofBliss,“uid”它是您自己的变量的名称,您可以使用任何重要的名称,例如“notificationID”,并将其存储在NSDictionary 中,其 id 的值与UILocalNotification 相关的实体。然后使用您的自定义数据将 notification.userInfo 属性设置为字典。现在,当您收到通知时,您可以使用该自定义 ID 或您需要的任何其他内容来区分它们。
        【解决方案5】:

        您可以像这样安排通知时保留一个带有类别标识符的字符串

                localNotification.category = NotificationHelper.categoryIdentifier
        

        然后搜索它并在需要时取消

        let  app = UIApplication.sharedApplication()
        
            for notification in app.scheduledLocalNotifications! {
                if let cat = notification.category{
                    if cat==NotificationHelper.categoryIdentifier {
                        app.cancelLocalNotification(notification)
                        break
                    }
        
                }
            }
        

        【讨论】:

          【解决方案6】:

          我稍微扩展了 KingofBliss 的答案,写得更像 Swift2,删除了一些不必要的代码,并添加了一些崩溃保护。

          首先,在创建通知时,您需要确保设置通知的 userInfo 的 uid(或任何自定义属性):

          notification.userInfo = ["uid": uniqueid]
          

          那么,在删除它的时候,你可以这样做:

          guard
              let app: UIApplication = UIApplication.sharedApplication(),
              let notifications = app.scheduledLocalNotifications else { return }
          for notification in notifications {
              if
                  let userInfo = notification.userInfo,
                  let uid: String = userInfo["uid"] as? String where uid == uidtodelete {
                      app.cancelLocalNotification(notification)
                      print("Deleted local notification for '\(uidtodelete)'")
              }
          }
          

          【讨论】:

          • 为了安全起见,你可以使用保护语句保护 let app = UIApplication.sharedApplication() else { return false } for schedualedNotif in app.scheduledLocalNotifications { ... } 然后你不需要强制在 for 循环中展开它
          【解决方案7】:

          我在 Swift 2.0 中使用这个函数:

            static func DeleteNotificationByUUID(uidToDelete: String) -> Bool {
              let app:UIApplication = UIApplication.sharedApplication()
              // loop on all the current schedualed notifications
              for schedualedNotif in app.scheduledLocalNotifications! {
                let notification = schedualedNotif as UILocalNotification
                let urrentUi = notification.userInfo! as! [String:AnyObject]
                let currentUid = urrentUi["uid"]! as! String
                if currentUid == uidToDelete {
                  app.cancelLocalNotification(notification)
                  return true
                }
              }
              return false
            }
          

          灵感来自@KingofBliss 的回答

          【讨论】:

            【解决方案8】:

            Swift 版本,如果需要:

            func cancelLocalNotification(UNIQUE_ID: String){
            
                    var notifyCancel = UILocalNotification()
                    var notifyArray = UIApplication.sharedApplication().scheduledLocalNotifications
            
                    for notifyCancel in notifyArray as! [UILocalNotification]{
            
                        let info: [String: String] = notifyCancel.userInfo as! [String: String]
            
                        if info[uniqueId] == uniqueId{
            
                            UIApplication.sharedApplication().cancelLocalNotification(notifyCancel)
                        }else{
            
                            println("No Local Notification Found!")
                        }
                    }
                }
            

            【讨论】:

              【解决方案9】:

              在swift中调度和removeNotification:

                  static func scheduleNotification(notificationTitle:String, objectId:String) {
              
                  var localNotification = UILocalNotification()
                  localNotification.fireDate = NSDate(timeIntervalSinceNow: 24*60*60)
                  localNotification.alertBody = notificationTitle
                  localNotification.timeZone = NSTimeZone.defaultTimeZone()
                  localNotification.applicationIconBadgeNumber = 1
                  //play a sound
                  localNotification.soundName = UILocalNotificationDefaultSoundName;
                  localNotification.alertAction = "View"
                  var infoDict :  Dictionary<String,String!> = ["objectId" : objectId]
                  localNotification.userInfo = infoDict;
              
                  UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
              }
                  static func removeNotification(objectId:String) {
                  var app:UIApplication = UIApplication.sharedApplication()
              
                  for event in app.scheduledLocalNotifications {
                      var notification = event as! UILocalNotification
                      var userInfo:Dictionary<String,String!> = notification.userInfo as! Dictionary<String,String!>
                      var infoDict :  Dictionary = notification.userInfo as! Dictionary<String,String!>
                      var notifcationObjectId : String = infoDict["objectId"]!
              
                      if notifcationObjectId == objectId {
                          app.cancelLocalNotification(notification)
                      }
                  }
              
              
              
              }
              

              【讨论】:

              • 不要滥用alertBodyfireDate 来识别通知;使用userInfo 字段来执行此操作,作为@KingOfBliss 详细信息的答案...
              • 是的,alertBody 不是识别通知的好选择。我将其更改为 userInfo
              【解决方案10】:

              您传递给cancelLocalNotification: 的 UILocalNotification 对象将匹配具有匹配属性的任何现有 UILocalNotification 对象。

              所以:

              UILocalNotification *notification = [[UILocalNotification alloc] init];
              notification.alertBody = @"foo";
              [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
              

              将显示一个本地通知,稍后可以通过以下方式取消:

              UILocalNotification *notification = [[UILocalNotification alloc] init];
              notification.alertBody = @"foo";
              [[UIApplication sharedApplication] cancelLocalNotification:notification];
              

              【讨论】:

              • 谢谢。我认为您正在创建一个新通知,然后将其取消。它不会对我之前安排的通知产生任何影响,它仍然会被触发。
              • 除了alertBody之外,还有什么可以匹配的属性吗?
              【解决方案11】:

              对于重复提醒(例如,您希望闹钟在周日、周六和周三下午 4 点响起,那么您必须发出 3 个闹钟并将 repeatInterval 设置为 NSWeekCalendarUnit )。

              只做一次提醒:

              UILocalNotification *aNotification = [[UILocalNotification alloc] init];
                              aNotification.timeZone = [NSTimeZone defaultTimeZone];
                              aNotification.alertBody = _reminderTitle.text;
                              aNotification.alertAction = @"Show me!";
                              aNotification.soundName = UILocalNotificationDefaultSoundName;
                              aNotification.applicationIconBadgeNumber += 1;
              
                              NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
                              NSDateComponents *componentsForFireDate = [calendar components:(NSYearCalendarUnit | NSWeekCalendarUnit|  NSHourCalendarUnit | NSMinuteCalendarUnit| NSSecondCalendarUnit | NSWeekdayCalendarUnit) fromDate: _reminderDate];
              
                              [componentsForFireDate setHour: [componentsForFireDate hour]] ; //for fixing 8PM hour
                              [componentsForFireDate setMinute:[componentsForFireDate minute]];
              
                              [componentsForFireDate setSecond:0] ;
                              NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForFireDate];
                              aNotification.fireDate = fireDateOfNotification;
                              NSDictionary *infoDict = [NSDictionary dictionaryWithObject:_reminderTitle.text forKey:kRemindMeNotificationDataKey];
                              aNotification.userInfo = infoDict;
              
                              [[UIApplication sharedApplication] scheduleLocalNotification:aNotification];
              

              重复提醒:

              for (int i = 0 ; i <reminderDaysArr.count; i++)
                              {
              
                                  UILocalNotification *aNotification = [[UILocalNotification alloc] init];
                                  aNotification.timeZone = [NSTimeZone defaultTimeZone];
                                  aNotification.alertBody = _reminderTitle.text;
                                  aNotification.alertAction = @"Show me!";
                                  aNotification.soundName = UILocalNotificationDefaultSoundName;
                                  aNotification.applicationIconBadgeNumber += 1;
              
                                  NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
                                  NSDateComponents *componentsForFireDate = [calendar components:(NSYearCalendarUnit | NSWeekCalendarUnit|  NSHourCalendarUnit | NSMinuteCalendarUnit| NSSecondCalendarUnit | NSWeekdayCalendarUnit) fromDate: _reminderDate];
              
              
                                  [componentsForFireDate setWeekday: [[reminderDaysArr objectAtIndex:i]integerValue]];
              
                                  [componentsForFireDate setHour: [componentsForFireDate hour]] ; // Setup Your Own Time.
                                  [componentsForFireDate setMinute:[componentsForFireDate minute]];
              
                                  [componentsForFireDate setSecond:0] ;
                                  NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForFireDate];
                                  aNotification.fireDate = fireDateOfNotification;
                                  aNotification.repeatInterval = NSWeekCalendarUnit;
                                  NSDictionary *infoDict = [NSDictionary dictionaryWithObject:_reminderTitle.text forKey:kRemindMeNotificationDataKey];
                                  aNotification.userInfo = infoDict;
              
                                  [[UIApplication sharedApplication] scheduleLocalNotification:aNotification];
                              }
                          }
              

              用于过滤您的数组以显示它。

              -(void)filterNotficationsArray:(NSMutableArray*) notificationArray{
              
                  _dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication] scheduledLocalNotifications]];
                  NSMutableArray *uniqueArray = [NSMutableArray array];
                  NSMutableSet *names = [NSMutableSet set];
              
                  for (int i = 0 ; i<_dataArray.count; i++) {
                      UILocalNotification *localNotification = [_dataArray objectAtIndex:i];
                      NSString * infoDict = [localNotification.userInfo objectForKey:@"kRemindMeNotificationDataKey"];
              
                      if (![names containsObject:infoDict]) {
                          [uniqueArray addObject:localNotification];
                          [names addObject:infoDict];
                      }
                  }
                  _dataArray = uniqueArray;
              }
              

              要删除提醒,即使它是一次或重复:

              - (void) removereminder:(UILocalNotification*)notification
              {
                  _dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication]scheduledLocalNotifications]];
              
                  NSString * idToDelete = [notification.userInfo objectForKey:@"kRemindMeNotificationDataKey"];
                  for (int i = 0 ; i<_dataArray.count; i++)
                  {
                      UILocalNotification *currentLocalNotification = [_dataArray objectAtIndex:i];
                      NSString * notificationId = [currentLocalNotification.userInfo objectForKey:@"kRemindMeNotificationDataKey"];
              
                      if ([notificationId isEqualToString:idToDelete])
                          [[UIApplication sharedApplication]cancelLocalNotification:currentLocalNotification];
                  }
              
                  _dataArray = [[NSMutableArray alloc]initWithArray:[[UIApplication sharedApplication]scheduledLocalNotifications]];
                  [self filterNotficationsArray:_dataArray];
                  [_remindersTV reloadData];
              
              }
              

              【讨论】:

                【解决方案12】:

                其他选项:

                首先,当你创建本地通知时,可以将它存储在用户默认值中以备将来使用,本地通知对象不能直接存储在用户默认值中,这个对象需要先转换成NSData对象,然后@ 987654321@可以存储到User defaults。下面是代码:

                NSData *data = [NSKeyedArchiver archivedDataWithRootObject:localNotif];
                [[NSUserDefaults standardUserDefaults] setObject:data forKey:[NSString  stringWithFormat:@"%d",indexPath.row]];
                

                在您存储并安排本地通知后,将来可能会要求您取消之前创建的任何通知,以便您可以从用户默认设置中检索它。

                NSData *data= [[NSUserDefaults standardUserDefaults] objectForKey:[NSString   stringWithFormat:@"%d",UniqueKey]];
                
                UILocalNotification *localNotif = [NSKeyedUnarchiver unarchiveObjectWithData:data];
                NSLog(@"Remove localnotification  are %@", localNotif);
                [[UIApplication sharedApplication] cancelLocalNotification:localNotif];
                [[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithFormat:@"%d",UniqueKey]];
                

                希望对你有帮助

                【讨论】:

                • 谢谢,我已经用第一种方式实现了,但你的回答也是正确的。我会考虑到这一点。你能告诉哪个更有效吗?谢谢你的帮助:)
                • @Yogi:如果你看第一个答案,如果你想取消本地通知,你需要每次运行 for 循环,但在上面的答案中,你不需要运行任何 for 循环,你可以直接访问本地通知并取消该本地通知并将其从用户默认值中删除,根据我的回答,这是更有效的方式
                • @JigneshBrahmkhatri 你的方法很有效。但是当用户卸载应用程序并重新安装时它会失败。
                • @KingofBliss,在这种情况下,我们必须取消所有通知,对吧?所以我想这个解决方案更快。 :)
                • @Sufian 要取消所有通知,有一种更快的方法 [[UIApplication sharedApplication] cancelAllLocalNotifications]; ;)
                【解决方案13】:

                这就是我的工作。

                创建通知时,请执行以下操作:

                  // Create the notification
                
                UILocalNotification *notification = [[UILocalNotification alloc]  init] ;
                
                
                
                notification.fireDate = alertDate;
                notification.timeZone = [NSTimeZone localTimeZone] ;
                notification.alertAction = NSLocalizedString(@"Start", @"Start");
                notification.alertBody = **notificationTitle**;
                notification.repeatInterval= NSMinuteCalendarUnit;
                
                notification.soundName=UILocalNotificationDefaultSoundName;
                notification.applicationIconBadgeNumber = 1;
                
                [[UIApplication sharedApplication] scheduleLocalNotification:notification] ;
                

                当试图删除它时这样做:

                 NSArray *arrayOfLocalNotifications = [[UIApplication sharedApplication] scheduledLocalNotifications] ;
                
                for (UILocalNotification *localNotification in arrayOfLocalNotifications) {
                
                    if ([localNotification.alertBody isEqualToString:savedTitle]) {
                        NSLog(@"the notification this is canceld is %@", localNotification.alertBody);
                
                        [[UIApplication sharedApplication] cancelLocalNotification:localNotification] ; // delete the notification from the system
                
                    }
                
                }
                

                此解决方案应适用于多个通知,并且您无需管理任何数组或字典或用户默认值。您只需使用已保存到系统通知数据库的数据即可。

                希望这对未来的设计师和开发人员有所帮助。

                编码愉快! :D

                【讨论】:

                • 感谢您分享您的答案,但是如果您的所有通知都具有相同的正文或要从用户那里获取正文,则此逻辑如何工作。在这种情况下,用户可以将相同的正文提供给多个通知。
                • @Yogi,和 alertbody 一样,你可以查看,notification.firedate 来获取所需的通知。感谢 abhi 提供了一个简单的解决方案。为你点赞 1
                • @NAZIK:感谢您对讨论的兴趣。但是用户仍然可以在同一触发日期安排两个通知,因为它是一个警报应用程序。至少它可以成为测试人员的测试用例,而这个解决方案看起来在那里失败了。
                • @Yogi,明智的测试,为什么我们不能检查 if ([localNotification.alertBody isEqualToString:savedTitle] || [localNotification.firedate ==something]),因为两个相同日期的通知应该包含不同的alertBody
                • 不要滥用alertBodyfireDate 来识别通知;使用userInfo 字段来执行此操作,作为@KingOfBliss 详细信息的答案...
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-04-10
                相关资源
                最近更新 更多