22
iOSハンズオントレーニング Delegate(委譲)Notification(通知)KVO(キー値監視) 大久保 聡

iOSハンズオントレーニング observer編 (delegate,notification,KVO)

Embed Size (px)

DESCRIPTION

Observerパターンについて、Delegate,Notification,KVOを使って実装する方法を学びます。

Citation preview

Page 1: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

iOSハンズオントレーニング Delegate(委譲)、Notification(通知)、KVO(キー値監視)

 大久保 聡

Page 2: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

目次Observerパターン

Delegate(委譲)

Notification(通知)

KVO : Key-Value Observing(キー値監視)

Page 3: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

ObserverパターンObserverパターンに登場するのは、2つのクラスだ。監視するクラスと、監視されて通知を行うクラスだ。監視するクラスの方を、Observerクラスと呼ぼう。もう一方の監視されるクラスの方は、Subjectクラスとする。

Page 4: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

Delegate(委譲)委譲元オブジェクトのポインタを移譲先オブジェクトで保持し、委譲先オブジェクトから委譲元オブジェクトのメソッドをコールする。・・・コールバック

Page 5: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

Delegate実装 (実装イメージ)

アルバムに写真を配置、写真がタップされたらその選ばれた写真の処理をしたい。

監視側のObserverクラスをUIView

監視される側のSubject

クラスをUIImageView

タップされたら親クラスのメソッドをコールバックする。

Page 6: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

Delegate実装 (Subjectクラスの作成)

UIImageViewクラスを新たに作成する。

UIImageViewクラスに、Observerクラスのポインタを保持するメンバ変数を追加する。

ユーザ操作を受け付けるように変更する。

self.userInteractionEnabled = YES;

タップされたら、Observerクラスのメソッドをコールする。

※ベースとなるプロジェクトをダウンロードしてください。 https://github.com/ovjang/NoUseStoryBoard_Observer

Page 7: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

// // PictureView.h // !#import <UIKit/UIKit.h> !@interface PictureView : UIImageView { @private NSObject *delegate_; } !@property NSObject *delegate; !@end

// // PictureView.m // !#import "PictureView.h" !@implementation PictureView @synthesize delegate = delegate_; !- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code self.userInteractionEnabled = YES; // UIImageViewはデフォルトでNoなので注意 } return self; } !- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if(delegate_ !=nil) { [delegate_ pictureSelected]; } } !@end

Page 8: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

Delegate実装 (プロトコルの作成)

プロトコルを新たに作成する。

subjectクラスのメンバ変数に、プロトコルを指定する。

タップされた際に呼ぶメソッドで、プロトコルに準拠していることを確認する。

Page 9: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

// // PictureView.h // !#import <UIKit/UIKit.h> #import "PictureViewDelegate.h" !@interface PictureView : UIImageView { @private NSObject <PictureViewDelegate> *delegate_; } @property NSObject <PictureViewDelegate> *delegate; @end

// // PictureView.m // !#import "PictureView.h" !@implementation PictureView @synthesize delegate = delegate_; !- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code self.userInteractionEnabled = YES; } return self; } !- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if(delegate_ !=nil) { if ([delegate_ conformsToProtocol:@protocol(PictureViewDelegate)]) { if ([delegate_ respondsToSelector:@selector(pictureSelected)]) { [delegate_ pictureSelected]; } } } } @end

// // PictureViewDelegate.h (javaでいうところのインターフェース) // !#import <Foundation/Foundation.h> !@protocol PictureViewDelegate <NSObject> @optional -(void)pictureSelected; // 抽象メソッド !@end

Page 10: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

Delegate実装 (Observerクラスの作成)

既存のUIViewControllerを、Observerクラスにします。また、プロトコルに準拠させる。

Subjectクラスを、newして画面に配置する。

Subjectクラスのメンバ変数に、自分のポインタを格納する。

プロトコルにあるメソッドを実装する。

Page 11: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

/ Screen1ViewController.m !#import "Screen1ViewController.h" #import "PictureView.h" !@interface Screen1ViewController () !@end !@implementation Screen1ViewController !- (id)init { self = [super init]; if (self) { // Custom initialization self.title = @"Album"; self.view.backgroundColor = [UIColor grayColor]; } return self; } !- (void)viewDidLoad { [super viewDidLoad]; UIImage* image01 = [UIImage imageNamed:@"picture01.jpeg"]; PictureView* uiImageView1 = [[PictureView alloc] initWithFrame:CGRectMake(10, 10, 100, 150)]; uiImageView1.delegate = self; uiImageView1.image = image01; [self.view addSubview:uiImageView1]; ! UIImage* image02 = [UIImage imageNamed:@"picture02.jpeg"]; PictureView* uiImageView2 = [[PictureView alloc] initWithFrame:CGRectMake(120, 10, 100, 150)]; uiImageView2.delegate = self; uiImageView2.image = image02; [self.view addSubview:uiImageView2]; } !-(void)pictureSelected { NSLog(@"Push"); } !@end

// Screen1ViewController.h !#import <UIKit/UIKit.h> #import "PictureViewDelegate.h" !@interface Screen1ViewController : UIViewController <PictureViewDelegate> !@end

Page 12: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

Notification(通知)仲介役がObserverクラスと、Subjectクラスのひも付けと連絡を行う。

Observer クラス NSnotificationCenter

Subject クラス

Tapって通知があったら教えてねOK

Observer クラス NSnotificationCenter

Subject クラス

Tapって通知を送る!!

Observer クラス NSnotificationCenter

Subject クラス

Tapって通知をあったよ!!通知あった

addObserver 通知があったら、これを コールバックしてね

postNotification

コールバック

Page 13: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

Notification実装 (NotificationCenterにObserber登録)

NSNotificationCenterを取得する。

Observerを登録する。知らせて欲しい通知と、知らせる際に呼び出してもらうセレクターを指定する。(この娘の返事だけ、教えてねということもできます。)

Page 14: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

// // Screen1ViewController.m // !#import "Screen1ViewController.h" #import "PictureView.h" !@interface Screen1ViewController () !@end !@implementation Screen1ViewController !- (id)init { self = [super init]; if (self) { // Custom initialization self.title = @"Album"; self.view.backgroundColor = [UIColor grayColor]; // NSNotificationCenterを取得する NSNotificationCenter* center; center = [NSNotificationCenter defaultCenter]; // Observerとして登録する [center addObserver:self selector:@selector(pictureSelected:) name:@"PictureTaped" object:nil]; } return self; }

Page 15: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

Notification実装 (通知を送る)

NSNotificationCenterを取得する。

送る通知(NSNotification)を作成する。

NSNotificationCenterに、通知を送る。

Page 16: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

// // PictureView.m // !#import "PictureView.h" !@implementation PictureView !- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code self.userInteractionEnabled = YES; } return self; } !- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // NSNotificationを作成する NSNotification* notification; notification = [NSNotification notificationWithName:@"PictureTaped" object:self userInfo:nil]; // NSNotificationCenterを取得する NSNotificationCenter* center; center = [NSNotificationCenter defaultCenter]; // 通知を行う [center postNotification:notification]; } !@end

// // PictureViewDelegate.h // !#import <Foundation/Foundation.h> !@protocol PictureViewDelegate <NSObject> @optional -(void)pictureSelected:(NSNotification *)notification; !@end

Page 17: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

Notification実装 (通知を受け取る)

コールバックされてくるメソッドで、通知(NSNotification)を受け取る。NSNotificationに含まれる情報、UserInfo(NSDictionary)の中身をもとに必要な処理を行う。

Page 18: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

// // Screen1ViewController.m // !#import "Screen1ViewController.h" #import "PictureView.h" !@interface Screen1ViewController () !@end !@implementation Screen1ViewController !- (id)init { self = [super init]; if (self) { // Custom initialization self.title = @"Album"; self.view.backgroundColor = [UIColor grayColor]; // NSNotificationCenterを取得する NSNotificationCenter* center; center = [NSNotificationCenter defaultCenter]; // Observerとして登録する [center addObserver:self selector:@selector(pictureSelected:) name:@"PictureTaped" object:nil]; } return self; } !- (void)viewDidLoad { [super viewDidLoad]; UIImage* image01 = [UIImage imageNamed:@"picture01.jpeg"]; PictureView* uiImageView1 = [[PictureView alloc] initWithFrame:CGRectMake(10, 10, 100, 150)]; uiImageView1.image = image01; uiImageView1.tag = 1; [self.view addSubview:uiImageView1]; ! UIImage* image02 = [UIImage imageNamed:@"picture02.jpeg"]; PictureView* uiImageView2 = [[PictureView alloc] initWithFrame:CGRectMake(120, 10, 100, 150)]; uiImageView2.image = image02; uiImageView2.tag = 2; [self.view addSubview:uiImageView2]; } !-(void)pictureSelected:(NSNotification*)notification { NSLog(@"Push %@",notification.userInfo); } !@end

Page 19: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

KVO(キー値監視)

キー値監視とは、ほかのオブジェクトに属する特定のプロパティの変化について通知をオブジェクトが受け取れるようにする仕組みです。(キー値監視に必要なメソッドは、ルートクラスであるNSObjectに実装されている。)

Page 20: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

KVO実装 (Subjectクラス)

// // KVOclass.h // !#import <Foundation/Foundation.h> !@interface KVOclass : NSObject { int value_; } @property int value; !@end

// // KVOclass.m // !#import "KVOclass.h" !@implementation KVOclass @synthesize value = value_; !@end

監視する値を持つクラスを作成する。

Page 21: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

KVO実装 (Subjectクラス)

Subjectクラスにオブザーバーを追加する。

OBserverクラスに、変更通知を受け取るメソッドを、オーバーライドする。

Page 22: iOSハンズオントレーニング observer編 (delegate,notification,KVO)

// // Screen1ViewController.m // !#import "Screen1ViewController.h" #import "KVOclass.h" @interface Screen1ViewController () !@end !@implementation Screen1ViewController !- (id)init { self = [super init]; if (self) { // Custom initialization self.title = @"KVO Test"; self.view.backgroundColor = [UIColor grayColor]; } return self; } !- (void)viewDidLoad { [super viewDidLoad]; ! KVOclass* kvo01 = [KVOclass new]; [kvo01 addObserver:self forKeyPath:@"value" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:nil]; ! KVOclass* kvo02 = [KVOclass new]; [kvo02 addObserver:self forKeyPath:@"value" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:nil]; kvo01.value = 1; // 値を変更 } !- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context { if ([keyPath isEqual:@"value"]) { NSLog(@"New Key = %@",[change objectForKey:NSKeyValueChangeNewKey]); } } !@end