删除特定的本地通知


92

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

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

我知道[[UIApplication sharedApplication] cancelLocalNotification:notification]方法,但是如何获得此“通知”以取消它呢?

Answers:


218

您可以在本地通知的userinfo中为key保存一个唯一值。获取所有本地通知,遍历数组并删除特定通知。

代码如下,

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;
    }
}

迅速:

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内容时,添加唯一标识符

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

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

有关更多信息,请访问UNUserNotificationCenter


@kingofBliss,您能否告诉我在“ uidtodelete”处给我。因为在我的情况下未声明。
ishhhh 2011年

@ishhh它只是一个strig值..您应该声明它并使用要删除的uid值对其进行初始化
KingofBliss

@ kingofBliss,uid总是在NSLog.dont konw中显示null如何摆脱此情况。请帮助我
ishhhh 2011年

@ishhh创建本地通知时,您是否在userinfo词典中存储了uid的任何值?我想你错过了。
KingofBliss 2011年

@kingofBliss,“ uid”是您自己的变量的名称,您可以使用任何重要的名称(例如“ notificationID”),并将其存储在带有NSDictionary与关联的实体的id的值中UILocalNotification。然后将notification.userInfo属性设置为包含您的自定义数据的字典。现在,当您收到通知时,可以使用该自定义ID或其他所需的内容来区分它们。
IgniteCoders 2014年

23

其他选择:

首先,创建本地通知时,可以将其存储在用户默认值中以备将来使用,不能将本地通知对象直接存储在用户默认值中,此对象需要先转换为NSData对象,然后NSData才能存储到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

1
@Yogi:如果您查看第一个答案,则要取消本地通知就需要每次都运行for循环,但是在上面的答案中,您将不需要运行任何for循环,您可以直接访问本地通知并取消该通知本地通知并将其从用户默认设置中删除,按照我的回答,这是一种更有效的方法
iMOBDEV 2011年

@JigneshBrahmkhatri您的方法有效。但是,当用户卸载应用程序并重新安装时,它将失败。
KingofBliss 2012年

@KingofBliss,在这种情况下,我们必须取消所有通知,对吗?所以我想这个解决方案更快。:)
Sufian

@Sufian要取消所有通知,有一种更快的方法[[UIApplication sharedApplication] cancelAllLocalNotifications]; ;)
KingofBliss

8

这是我的工作。

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

  // 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一样,您可以检查,通知.firedate以获得所需的通知。感谢abhi提供的简单解决方案
。upvote1

1
@NAZIK:感谢您对讨论的关注。但是用户仍然可以在相同的触发日期安排两个通知,因为它是警报应用程序。至少对于测试人员而言,这可能是一个测试用例,而该解决方案似乎在那里失败了。
瑜伽士

@瑜伽,明智的测试,为什么我们不能检查([localNotification.alertBody isEqualToString:savedTitle] || [localNotification.firedate == something]),因为具有相同日期的两个通知应包含不同的alertBody
Azik Abdullah

请勿滥用alertBodyfireDate标识通知;使用userInfo领域这样做的,由@KingOfBliss细节的答案...
塞弗林

8

快速调度和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)
        }
    }



}

1
请勿滥用alertBodyfireDate标识通知;使用userInfo领域这样做的,由@KingOfBliss细节的答案...
塞弗林

是的,alertBody不是识别通知的好选择。我将其更改为userInfo
Roman Barzyczak 2015年

6

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

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

  • 在创建一个本地通知,使用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")
}

为我工作。其他所有建议都不是,因为数组为空。
Maksim Kniazev'7

对iOS 10有任何想法吗?
Danpe

1
@Danpe:看看一节“管理递送通知”在这里:developer.apple.com/reference/usernotifications/...
Rygen

Xcode处理的带有次要mod的swift 3为我工作。
beshio

@beshio:感谢大家的注意。我已经更新了它的语法。
雷根(Rygen)'17年

4

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!")
            }
        }
    }

4

Swift 4解决方案:

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

2

在安排通知时,您可以保留带有类别标识符的字符串,如下所示

        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
            }

        }
    }

1

您传递给的UILocalNotification对象cancelLocalNotification:将匹配具有匹配属性的任何现有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];

1
谢谢。我认为您正在创建一个新通知,然后将其取消。它不会对我之前预定的通知产生任何影响,并且仍然会被触发。
瑜伽士

除alertBody之外,是否有任何可以匹配的属性?
Shamsiddin '16

1

我在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的答案


1

迅捷的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])

0

对于重复提醒(例如,您希望您的警报在下午4点在Sun,Sat和Wed处触发,那么您必须发出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];

}

0

我稍微扩展了KingofBliss的答案,使其更加类似于Swift2,删除了一些不必要的代码,并添加了一些崩溃防护。

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

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)'")
    }
}

1
为了安全起见,您可以使用保护声明保护器let app = UIApplication.sharedApplication()else {return false} for app.scheduledLocalNotifications {...} for schedualedNotif然后,您无需在for循环中强行将其解包
troligtvis
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.