iOSハンズオントレーニング observer編 (delegate,notification,KVO)
-
Upload
satosi-okubo -
Category
Technology
-
view
2.437 -
download
3
description
Transcript of iOSハンズオントレーニング observer編 (delegate,notification,KVO)
iOSハンズオントレーニング Delegate(委譲)、Notification(通知)、KVO(キー値監視)
大久保 聡
目次Observerパターン
Delegate(委譲)
Notification(通知)
KVO : Key-Value Observing(キー値監視)
ObserverパターンObserverパターンに登場するのは、2つのクラスだ。監視するクラスと、監視されて通知を行うクラスだ。監視するクラスの方を、Observerクラスと呼ぼう。もう一方の監視されるクラスの方は、Subjectクラスとする。
Delegate(委譲)委譲元オブジェクトのポインタを移譲先オブジェクトで保持し、委譲先オブジェクトから委譲元オブジェクトのメソッドをコールする。・・・コールバック
Delegate実装 (実装イメージ)
アルバムに写真を配置、写真がタップされたらその選ばれた写真の処理をしたい。
監視側のObserverクラスをUIView
監視される側のSubject
クラスをUIImageView
タップされたら親クラスのメソッドをコールバックする。
Delegate実装 (Subjectクラスの作成)
UIImageViewクラスを新たに作成する。
UIImageViewクラスに、Observerクラスのポインタを保持するメンバ変数を追加する。
ユーザ操作を受け付けるように変更する。
self.userInteractionEnabled = YES;
タップされたら、Observerクラスのメソッドをコールする。
※ベースとなるプロジェクトをダウンロードしてください。 https://github.com/ovjang/NoUseStoryBoard_Observer
// // 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
Delegate実装 (プロトコルの作成)
プロトコルを新たに作成する。
subjectクラスのメンバ変数に、プロトコルを指定する。
タップされた際に呼ぶメソッドで、プロトコルに準拠していることを確認する。
// // 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
Delegate実装 (Observerクラスの作成)
既存のUIViewControllerを、Observerクラスにします。また、プロトコルに準拠させる。
Subjectクラスを、newして画面に配置する。
Subjectクラスのメンバ変数に、自分のポインタを格納する。
プロトコルにあるメソッドを実装する。
/ 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
Notification(通知)仲介役がObserverクラスと、Subjectクラスのひも付けと連絡を行う。
Observer クラス NSnotificationCenter
Subject クラス
Tapって通知があったら教えてねOK
Observer クラス NSnotificationCenter
Subject クラス
Tapって通知を送る!!
Observer クラス NSnotificationCenter
Subject クラス
Tapって通知をあったよ!!通知あった
addObserver 通知があったら、これを コールバックしてね
postNotification
コールバック
Notification実装 (NotificationCenterにObserber登録)
NSNotificationCenterを取得する。
Observerを登録する。知らせて欲しい通知と、知らせる際に呼び出してもらうセレクターを指定する。(この娘の返事だけ、教えてねということもできます。)
// // 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; }
Notification実装 (通知を送る)
NSNotificationCenterを取得する。
送る通知(NSNotification)を作成する。
NSNotificationCenterに、通知を送る。
// // 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
Notification実装 (通知を受け取る)
コールバックされてくるメソッドで、通知(NSNotification)を受け取る。NSNotificationに含まれる情報、UserInfo(NSDictionary)の中身をもとに必要な処理を行う。
// // 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
KVO(キー値監視)
キー値監視とは、ほかのオブジェクトに属する特定のプロパティの変化について通知をオブジェクトが受け取れるようにする仕組みです。(キー値監視に必要なメソッドは、ルートクラスであるNSObjectに実装されている。)
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
監視する値を持つクラスを作成する。
KVO実装 (Subjectクラス)
Subjectクラスにオブザーバーを追加する。
OBserverクラスに、変更通知を受け取るメソッドを、オーバーライドする。
// // 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