#はじめに
ゴールは
RemoteNotificationをアプリの起動条件関係なく画面表示させたい
です。
AppDelegateで通知を受け取った後の挙動については
選択肢はいくつかあります。
- Delegate
- NSNotification
- KVO
ブロードキャストで通知するControllerは、Observerを大量に使用する場合でなく
今回は表になっている画面にだけ送る仕様にしました。
NSNotificationの使用自体は1:Nに送る場合に便利な機能として知られていて
実装自体が簡易にできてしまうので、Delegateを使うよりNSNotificationを使う方が多い印象があります。
オーバーヘッドが、という話でNSNotificationは使ってなかったのもあり
今回使ってみました。
#実装
ViewController、とNavigationControllerを使う場合で検討します。
##画面構成
##方針
画面数もほどほどあり、ControllerViewに都度書くのが非効率なので
スーパークラスに実装して派生するようにしました。
構成の所にあるNavigationController以外のSubClassのViewControllerは
@interface TopViewController : BasicViewController
ControllerViewでは
- 画面遷移
- 通知された時の挙動
を個別で書くようにします。
##コード
#define kDidReceiveRemoteNotification @"UIApplicationDidReceiveRemoteNotification"
Const.hはAppDelegate.hとBasicViewController.hでimportしています。
#import <UIKit/UIKit.h>
#import "Const.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}
return YES;
}
//(略)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
switch (application.applicationState) {
case UIApplicationStateActive:
NSLog(@"StateActive");
break;
case UIApplicationStateInactive:
NSLog(@"StateInactive");
break;
case UIApplicationStateBackground:
NSLog(@"StateBackground");
break;
default:
break;
}
[[NSNotificationCenter defaultCenter]
postNotificationName:kDidReceiveRemoteNotification
object:self
userInfo:userInfo];
}
#import <UIKit/UIKit.h>
#import "Const.h"
@interface BasicViewController : UIViewController
- (void)didReceiveRemoteNotification:(NSNotification *)notification;
@end
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(didReceiveRemoteNotification:)
name:kDidReceiveRemoteNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:kDidReceiveRemoteNotification
object:nil];
[super viewWillDisappear:animated];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)didReceiveRemoteNotification:(NSNotification *)notification
{
NSLog(@"%s %@",__func__,[notification.userInfo description]);
}
#RemoteNotification以外の補足
##画面遷移
- (IBAction)dismiss:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
UINavigationControllerが親にいる場合
- (IBAction)dismiss:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
##個別にメソッドをoverride
BasicViewController.m
のdidReceiveRemoteNotification:
をそれぞれのControllerで実装を変えてみます。
- (void)didReceiveRemoteNotification:(NSNotification *)notification
{
NSLog(@"%s %@",__func__,[notification.userInfo description]);
}
↓
- (void)didReceiveRemoteNotification:(NSNotification *)notification
{
//アラートを表示したり、表示データを変更したり
NSLog(@"%s %@",__func__,[notification.userInfo description]);
UIAlertController *alertController =
[UIAlertController alertControllerWithTitle:@"Alert" message:@"iOS8" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alertController animated:YES completion:^{
[UIView animateWithDuration:0.8 delay:3
options:UIViewAnimationOptionCurveEaseOut
animations:^{
alertController.view.alpha = 0.0;
}
completion:^(BOOL finished){
[alertController dismissViewControllerAnimated:NO completion:nil];
}
];
}];
}
#参考URL
iOSハンズオントレーニング observer編 (delegate,notification,KVO)
http://www.slideshare.net/SatosiOkubo/ios-observer-delegatenotificationkvo
[iOS SDK] [memo] NSNotification or KVO or delegate ?
https://hirooka.pro/?p=5124
KVO vs NSNotification vs protocol/delegates?
http://stackoverflow.com/questions/7864838/kvo-vs-nsnotification-vs-protocol-delegates
What is the difference between NSNotificationCenter and the Key Value Observing technique?
http://stackoverflow.com/questions/7040734/what-is-the-difference-between-nsnotificationcenter-and-the-key-value-observing
NSNotification & NSNotificationCenter
http://nshipster.com/nsnotification-and-nsnotificationcenter/
#さいごに
普段やらない方法で
普通に、簡単に、通知を送れる内容だったのですが
アプリのライフサイクルやEventの通知など選択肢に対する条件を検討する必要があることがわかりました。
今のやり方だと、NotificationをRemoveしている場合のタイミングの受信を
スルーしてしまう問題点がみえます。
viewWillDisappear、viewDidDisappearの記述も間違っていました
viewDidDisappearだと次画面のviewDidLoad後、viewDidAppear前に発生していることになります(すみません)。
結局Delegateがいいのか、というと、どうなんでしょう。今は決着がついたのでしょうか。