特定のローカル通知を削除する


92

ローカル通知に基づいてiPhoneアラームアプリを開発しています。

アラームを削除すると、関連するローカル通知がキャンセルされます。しかし、ローカル通知の配列からキャンセルするオブジェクトを正確に判断するにはどうすればよいですか?

私は[[UIApplication sharedApplication] cancelLocalNotification:notification]方法を知っていますが、この「通知」を取得してキャンセルするにはどうすればよいですか?

回答:


218

ローカル通知のユーザー情報にキーの一意の値を保存できます。すべてのローカル通知を取得し、配列をループして、特定の通知を削除します。

次のようにコーディングし、

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:

UserNotification(iOS 10以降)を使用している場合は、次の手順に従ってください。

  1. UserNotificationコンテンツを作成するときに、一意の識別子を追加します

  2. removePendingNotificationRequests(withIdentifiers :)を使用して、特定の保留中の通知を削除します

  3. removeDeliveredNotifications(withIdentifiers :)を使用して、配信された特定の通知を削除します

詳細については、UNUserNotificationCenter


@kingofBliss、私の場合は宣言されていないので、 "uidtodelete"で指定するように教えてください。
ishhhh 2011

@ishhhその単なるstrig値..宣言して、削除するuidの値で初期化する必要があります
KingofBliss

@kingofBliss、uidは常にNSLogでnullを表示しています。これを取り除く方法を知ってはいけません。助けてください
ishhhh

@ishhhローカル通知を作成するときに、userinfo辞書にuidの値を保存しましたか?あなたはそれを逃したと思います。
KingofBliss、2011年

@kingofBliss、「uid」は独自の変数の名前です。「notificationID」などの重要な名前を使用NSDictionaryして、に関連するエンティティのIDの値とともにそれをaに保存できますUILocalNotification。次に、notification.userInfoプロパティをカスタムデータを含むディクショナリに設定します。これで、通知を受け取ったときに、そのカスタムIDまたは必要なその他のものでそれらを区別できます。
IgniteCoders 14年

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

@JigneshBrahmkhatriあなたの方法は効果的です。しかし、ユーザーがアプリをアンインストールして再インストールすると失敗します。
KingofBliss 2012年

@KingofBliss、その場合、すべての通知をキャンセルする必要がありますよね?したがって、このソリューションの方が速いと思います。:)
スーフィアン2013年

@Sufianすべての通知をキャンセルするには、はるかに高速な方法があります[[UIApplication sharedApplication] cancelAllLocalNotifications]; ;)
KingofBliss 2013年

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と同様に、notification.firedateをチェックして必要な通知を取得できます。シンプルなソリューションのabhiに感謝します。uptote1 for u
Azik Abdullah 2012

1
@NAZIK:ディスカッションに関心をお寄せいただきありがとうございます。ただし、アラームアプリケーションであるため、ユーザーは同じ発砲日に2つの通知をスケジュールできます。少なくともそれはテスターのテストケースである可能性があり、このソリューションはそこで失敗しているようです。
ヨギ

ヨギ@、賢明なテスト、なぜ([localNotification.alertBody isEqualToString:savedTitle] || [localNotification.firedate ==何か])場合は、我々はチェックカント同じ日付を持つ2つの通知が異なるalertBodyが含まれている必要があるため、
Azikアブドラ

alertBodyまたはfireDate通知を識別するために乱用しないでください。userInfo@KingOfBlissの詳細による回答として、これを行うためにフィールドを使用します...
severin

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
alertBodyまたはfireDate通知を識別するために乱用しないでください。userInfo@KingOfBlissの詳細による答えとして、これを行うためにフィールドを使用します...
severin

はいalertBodyは通知を識別するための良いオプションではありません。私はそれをuserInfoに変更しました
Roman Barzyczak

6

iMOBDEVのソリューションは、特定の通知を削除するために完全に機能します(たとえば、アラームを削除した後)が、既に発動済みでまだ通知センターにある通知を選択的に削除する必要がある場合に特に役立ちます。

考えられるシナリオは次のとおりです。アラームの通知は発生しますが、ユーザーはその通知をタップせずにアプリを開き、そのアラームを再度スケジュールします。特定のアイテム/アラームの通知センターに通知を1つだけ含めることができるようにする場合は、これが良い方法です。また、アプリを開くたびにすべての通知をクリアする必要がないため、アプリに適しています。

  • ローカル通知を作成し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 16

iOS 10のアイデアは?
Danpe、2016

1
@Danpe:ここでは、「納入通知の管理」のセクションを見てみましょう:developer.apple.com/reference/usernotifications/...
Rygen

Xcodeが処理するマイナーMODを備えたswift 3で私のために働いた。
beshio 2017

@beshio:頭を上げてくれてありがとう。構文を更新しました。
Rygen 2017

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
ありがとう。新しい通知を作成してからキャンセルしていると思います。それは以前にスケジュールされた通知に影響を与えず、それでも発生します。
Yogi

alertBody以外のプロパティに一致する可能性のあるプロパティはありますか?
Shamsiddin

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時に発火させたい場合、3つのアラームを作成し、repeatIntervalをNSWeekCalendarUnitに設定する必要があります)。

1回限りのリマインダーを作成する場合:

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
安全のために、guard-statement guard let app = UIApplication.sharedApplication()else {return false} for app.scheduledLocalNotifications {...}を使用すると、forループで強制的にアンラップする必要がありません
troligtvis
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.