[iOS] 로컬 알림 취소 – UILocalNotification 저장 및 취소

이전 포스팅  [iOS] 로컬 알림 (Local Notifications)에 이어 로컬 알림 저장 및  취소에 대해 좀 더 정리해보려 한다.

이전 포스팅에서도 언급 했지만, 알림 취소의 의미는

  • 알림 대기 중인 알림의 취소
  • 이미 도착한 알림의 취소 (iOS 디바이스 알림 센터 목록에서의 삭제)

로 구분된다.

알림 등록에 사용한 UILocalNotification을 저장하지 않고 알림을 취소하는 방법은 아래와 같다. (로컬 알림과 연계된 application delegate 메소드 내용은 이전 포스팅 참고)

// (1) 모든 알림 취소
// 임의의 메소드에서 다음 코드로 가능

[[UIApplication sharedApplication] cancelAllLocalNotifications];

// (2) 특정 알림 취소. Application delegate 파라미터 이용

// (2-1)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

    UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];

    if(localNotif){

        ...
        [application cancelLocalNotification:localNotif];
    }

    ...
    return YES;

}

// (2-2)
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    ...
    [application cancelLocalNotification:notification];
    ...
}

위 코드 (1) 방법은 앱에 등록된, 삭제되지 않은 모든 알림을 삭제한다. 알림센터에 보여지는 알림도 포함된다. (2) 방법은 도착한 알림만 삭제하여 알림센터에 보이지 않도록 한다.

간단한 알림의 경우 위 방법으로도 충분하다. 사용자가 알림 시각을 변경하면 기존에 등록된 알림을 cancelAllLocalNotifications로 지우고 새로 등록한다. 알림이 도착하면 application delegate에서 알림을 취소하여 확인된 알림이 알림센터에 보이지 않도록 한다.

그럼 어떠한 경우에 UILocalNotification을 저장해야 할까?

  • 어플리케이션에서 사용하는 로컬 알림의 종류가 다양하고 많을 경우, 
  • Application delegate 이외의 다른 이벤트에서 알림센터의 알림 항목을 삭제하고 싶은 경우

앱에서 사용하는 로컬 알림의 종류가 다양하고 – 특정 시간에 보내는 알림, 바로 보내는 알림등 앱 내에서 성격에 따라 구분 – 개수가 많다면, 하나의 알림을 취소하기 위해 cancelAllLocalNotifications으로 모든 알림을 지우고 다시 새로 등록하는 구조는 바람직하지 않다. 취소하고자 하는 알림만 취소하는 것이 효율적이다.

수신한 알림이 사용자가 원할 때까지 – 사용자가 확인한 경우에도 – 알림센터에 남아있길 원하는 경우에도 UILocalNotification을 저장하여 필요 시점에 취소해야 한다.

UILocalNotification 저장 시 NSUserDefaults를 이용하면 편하다. 직접 UILocalNotification 객체를 NSData로 변환 후 파일에 저장할 수 있지만 NSUserDefaults는 이를 쉽게 해준다.

(NSUserDefaults가 UILocalNotification 저장소로 적합한가에 대해서는 검토가 좀 더 필요하다. 본인도 스택오버플로우 검색을 통해 NSUserDefaults를 알았는데, 해당 클래스는 사용자의 앱 설정값 등 간단한 데이터를 저장하는 용도로 만들어졌다. 일단 지금까지 본인이 테스트한 바로는 문제가 발생하지 않았다.)

아래는 NSUserDefaults를 이용하여 UILocalNotification을 저장하고 반환하여 로컬 알림을 취소하는 예제 코드다.

//
// 로컬 알림 등록 메소드에서 UILocalNotification 저장
-(void)fireLocalNotification{

    // UILocalNotification 객체 생성
    UILocalNotification *noti = [[UILocalNotification alloc]init];
    noti.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];
    noti.timeZone = [NSTimeZone systemTimeZone];
    noti.alertBody = @"Just Do It";

    // UILocalNotification 을 NSData로 변환.
    // NSKeyedArchiver 이용
    NSData *notiData = [NSKeyedArchiver archivedDataWithRootObject:noti];

    // NSUserDefaults에 NSData 변환된 UILocalNotification 저장
    // 키값으로 알림메시지 사용 (테스트용)
    [[NSUserDefaults standardUserDefaults] setObject:notiData forKey:noti.alertBody];

    // 어플리케이션에 알림 등록
    [[UIApplication sharedApplication] scheduleLocalNotification:noti];
}

// 로컬 알림 취소
-(void)cancelLocalNotification:(NSString*)key{

    // key 값으로 NSData 타입의 UILocalNotification 획득
    // 파라미터 key는 저장시 등록한 값과 동일 가정
    NSData *dataNoti = [[NSUserDefaults standardUserDefaults] objectForKey:key]

    // NSData 타입을 UILocalNotification으로 변환
    // NSKeyedUnarchiver 이용
    UILocalNotification *notif = [NSKeyedUnarchiver unarchiveObjectWithData:dataNoti];

    // NSUserDefaults에 저장된 UILocalNotification 이용하여 알림 삭제
    [[UIApplication sharedApplication] cancelLocalNotification:notif];
}

NSUserDefaults에 저장할 수 있는 데이터 타입은 Property Lists에 사용되는 타입으로 NSArray, NSDictionary 등 다양하다. 위 코드에서는 UILocalNotification을 NSData 타입으로 저장하고 반환하였지만, 콜렉션 타입을 이용한다면 다른 방법으로도 가능하다. NSUserDefaults Class Reference를 확인하자.

NSObject와 NSData 간의 변환은 NSKeyedArchiver와 NSKeyedUnarchiver를 이용한다.

테스트 중 저장된 UILocalNotification을 이용한 알림 취소가 실패하는 경우를 발견하였다.

  • [UIApplication scheduleLocalNotification:]로 알림 등록 – 정상적으로 취소
  • [UIApplication presentLocalNotificationNow:]로 알림 등록 –  알림 취소 되지 않음 (디바이스 알림센터에서 알림이 삭제되지 않고 보임)

참고로 Application delegate 의 파라미터를 이용한 알림 취소는 위 두 메소드 모두 잘 된다.

iOS SDK를 찾아봤으나 정확한 원인을 밝힐 수  없었다. 두 메소드 간의 어떤 차이점이 이런 현상을 유발했는지 궁금하다.

Advertisements
Leave a comment

3 Comments

  1. tulurira

     /  March 8, 2013

    UILocalNotification 관련해서 공부중에 많은 참고가 되었습니다. 감사합니다 (__)
    개인적으로 궁금한 점이 있어서 질문 드려도 될까요 ?

    알람 앱은 대부분 snooze? 같이 사용자가 푸쉬 확인을 안하면 “반복해서 보내기”와 같은 기능을 기본으로
    지원하고 있는데요.

    api가 있는 줄 알고 검색을 해봤는데 아무래도 관련 기능은 없는 것 같아서요.
    이런 반복해서 보내기와 같은 기능 구현은 어떤 식으로 가능한지 궁금해서 글 남깁니다.

    Reply
    • snooze 버튼을 사용자가 클릭하면 서비스에서 지정된(또는 사용자가 지정한 알림 지연 시간)에 알림이 가도록 알림을 새로 등록하면 될것 같습니다.

      로컬 알림과 푸쉬 알림은 방식이 약간 다른 것 같습니다만(저도 푸쉬는 아직 제대로 보지 않아서..) 사용자가 snooze버튼을 선택한 이벤트는 두 경우 모두 받을 수 있으므로 처리가 가능할 것 같습니다.

      정리하면 로컬알림의 경우 사용자의 이벤트(snooze 같은)를 받으면 기존 알림은 삭제하고 알림을 새로 등록하면 될 것 같습니다.

      코멘트 감사드리며 추가 의견 주시면 더 의견 나누겠습다.

      Reply
    • 사용자가 알림을 확인했는지 여부는 사용자의 특정 이벤트(snooze 버튼 클릭과 같은) 없이 알기는 어려우나 알림 발행 시각을 저장해놨다가 알림으로 연결되는 페이지 로딩 여부와 비교하면 구현은 가능할 것 같기도 하네요.

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: