取消本地通知

48

我有一个关于UILocalNotification的问题。

我正在使用我的方法安排通知。

- (void) sendNewNoteLocalReminder:(NSDate *)date  alrt:(NSString *)title
{
    // some code ...
    UILocalNotification *localNotif = [[UILocalNotification alloc] init]; 

    if (localNotif == nil)  
        return;

    localNotif.fireDate = itemDate; 
    localNotif.timeZone = [NSTimeZone defaultTimeZone];
    localNotif.alertAction = NSLocalizedString(@"View Details", nil); 
    localNotif.alertBody = title;
    localNotif.soundName = UILocalNotificationDefaultSoundName; 
    localNotif.applicationIconBadgeNumber = 0;

    NSDictionary *infoDict = [NSDictionary dictionaryWithObject:stringID forKey:@"id"]; 
    localNotif.userInfo = infoDict; 

    [[UIApplication sharedApplication] scheduleLocalNotification:localNotif]; 
    [localNotif release];
}

它能够正常工作,我可以正确地接收通知。问题在于我应该如何取消通知。我正在使用这个方法。

- (void) deleteNewNoteLocalReminder:(NSString*) reminderID noteIDe:(NSInteger)noteIDE
{
    [[UIApplication sharedApplication] cancelLocalNotification:(UILocalNotification *)notification ????  
}

我不确定该怎么做,但我的问题是:

如何知道应删除哪个 UILocalNotification 对象?
有没有一种方法可以列出所有通知?

我唯一拥有的是我应该删除哪个提醒的 ID。
我正在考虑将 UILocalNotification 对象保存在我的“Note”对象中,并通过这种方式获取它,当我保存到我的 SQLite 数据库时序列化对象等... 是否有更聪明的方法?

10个回答

92

我的解决方案是使用UILocalNotificationuserInfo字典。实际上,我的做法是为每个通知生成一个唯一ID(当然,我能够在以后检索到这个ID),然后当我想取消与给定ID相关联的通知时,我将简单地使用数组扫描所有可用的通知:

[[UIApplication sharedApplication] scheduledLocalNotifications]

然后我尝试通过调查ID来匹配通知。例如:


NSString *myIDToCancel = @"some_id_to_cancel";
UILocalNotification *notificationToCancel=nil;
for(UILocalNotification *aNotif in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
  if([[aNotif.userInfo objectForKey:@"ID"] isEqualToString:myIDToCancel]) {
     notificationToCancel=aNotif;
     break;
  }
}
if(notificationToCancel) [[UIApplication sharedApplication] cancelLocalNotification:notificationToCancel];

我不知道这种方法是否比归档/取消归档更好,但它有效并将要保存的数据限制为仅一个ID。

编辑:有一个括号缺失


我尝试了你的方法,但对我无效。你能告诉我哪里出了问题吗?https://dev59.com/s2DVa4cB1Zd3GeqPZQuI - Farini
2
你的解决方案中没有使用我的方法。我的解决方案传递一个ID,而你使用整个对象。从你的代码来看,通知对象可能会被早期释放,这就是为什么会出现“未识别的选择器”的原因(当旧对象位置已被另一种类型的对象重用时,通常会发生这种情况)。在发送cancelNotification消息之前,尝试获取对象的类名以进行挖掘,这可能有助于调试。此外,当你分配“theNotification”时,请使用“self.theNotification = ...”而不是“theNotificaiton = ...”。 - viggio24
非常感谢!你真的激励了我,在每个单元格上添加了一个按钮,我可以在其中取消本地通知 atindex [sender tag],它比带来 uialertview 更好用。正如你所说,对象的名称现在就在取消之前,它完美地工作了! - Farini
是的,我已经看到了你在问题中的“自答”。我同意你的观点,针对你特定的情况,在其选择器上添加按钮然后取消通知是完全有效的。 - viggio24
如果使用 CoreData,我发现使用唯一的托管对象ID非常有帮助:NSManagedObjectID *moID = [managedObject objectID];。因为在保存后 CoreData 才会分配一个永久ID,所以你可以使用:BOOL isTemporary = [[managedObject objectID] isTemporaryID]; - d.ennis
显示剩余3条评论

57
您可以从scheduledLocalNotifications获取所有已预定的通知列表,或者您可以取消它们所有:

scheduledLocalNotifications

  [[UIApplication sharedApplication] cancelAllLocalNotifications];

2
我知道有cancelAllLocalNotifications,但我只想取消一个特定的通知。ScheduledLocalNotifications也许可以做到这一点...我会尝试一下。 - f0rz

13

我的解决方案是使用NSKeyedArchiver归档您已安排的UILocalNotification对象,并将其存储在某个地方(首选是plist中)。然后,当您想要取消该通知时,请查找正确的数据并使用NSKeyedUnarchiver进行反归档。

代码非常简单:

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:notice];
并且
UILocalNotification *notice = [NSKeyedUnarchiver unarchiveObjectWithData:data];

您还可以使用Base64编码序列化archievedDataWithRootObject中的NSData,然后保存到您已经拥有的JSON对象中。 - Rafael Sanches
@RafaelSanches 对于打扰你,我道歉。 但如果目标是存储/检索uilocalnotification以供稍后删除,那么使用JSON对象的优点是什么? - iamdavidlam

6
我的解决方案是,在创建UILocalNotification时,同时创建一个NSMutableDictionary,将该通知作为键值对的值存储,并以您的ID作为键。然后将这个NSMutableDictionay存储到您的NSUserDefaults中。
因此,当您想要取消任何特定的本地通知时,您可以写下[dictionary valueforkey @"KEY"],其中作为键的ID,以便获取该特定的本地通知并传递给它。
 [[UIApplication sharedApplication] scheduleLocalNotification:localNotif]; 

5

Swift 5:

UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: arrayContainingIdentifiers)

1
如果任何 Xamarin 开发者在寻找答案,这个对我来说非常有效。UNUserNotificationCenter.Current.RemovePendingNotificationRequests(new string[] { NotificationId }); - Sergey Ivanov

3

在Swift中,您首先通过以下方式将字典添加到通知的userInfo中:

let dict:NSDictionary = ["ID" : "someString"]
notification.userInfo = dict as! [String : String]

那么,你需要获取现有通知的数组(2),并逐个迭代遍历每个通知(3),直到找到你要查找的通知。一旦找到它,就可以取消它(4)。

// 1. Pass in the string you want to cancel
func cancelLocalNotification(uniqueId: String){

    // 2. Create an array of notifications, ensuring to use `if let` so it fails gracefully
    if let notifyArray = UIApplication.sharedApplication().scheduledLocalNotifications {

        // 3. For each notification in the array ...
        for notif in notifyArray as [UILocalNotification] {
            // ... try to cast the notification to the dictionary object
            if let info = notif.userInfo as? [String: String] {

                // 4. If the dictionary object ID is equal to the string you passed in ...
                if info["ID"] == uniqueId {
                    // ... cancel the current notification
                    UIApplication.sharedApplication().cancelLocalNotification(notif)
                }
            }
        }
    }
}

注意:UIApplication.sharedApplication()现在是UIApplication.shared。 - Andrea Leganza

2

Swift版本:

UIApplication.sharedApplication().cancelAllLocalNotifications()

1

使用userinfo取消特定“本地通知”的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!")
            }
        }
    }

0

感谢 @viggio24 给出的好答案,以下是 Swift 版本。

var notifyCancel = UILocalNotification()
var notifyArray=UIApplication.sharedApplication().scheduledLocalNotifications
var i = 0
while(i<notifyArray.count){
    if let notify = notifyArray[i] as? UILocalNotification{
        if let info = notify.userInfo as? Dictionary<String,String> {
            if let s = info["name"] {
                if(name==s){//name is the the one you want cancel
                    notifyCancel = notify
                    break
                }
            }
        }
    }
i++
}

不需要while和if let notify,只需简短地使用for notify in notifyArray as [UILocalNotification] { if let info = notifier.userInfo as? Dictionary<String,String> {...}} - Nitro.de

0
我的解决方案是在这些方法中删除所有已安排的通知。
-applicationDidFinishLaunchingWithOptions: 
- (void)applicationDidBecomeActive:(UIApplication *)application;
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;

使用

[[UIApplication sharedApplication] cancelAllLocalNotifications];

您仍然可以通过以下方式访问激活应用程序的本地通知对象。

    UILocalNotification *localNotif = [launchOptions objectForKey: UIApplicationLaunchOptionsLocalNotificationKey];

然后我在新的通知上重新安排时间。

- (void)applicationDidEnterBackground:(UIApplication *)application;

这样可以避免为所有通知进行簿记。我还在userInfo字典中发送一些上下文信息。这有助于跳转到应用程序中的正确位置。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接