2010年10月27日水曜日

「Cocoa Notification (NSNotification,NSNotificationCenter)」と「キー値監視」(5)

少し時間があいたけど放置せずに続き書く。
前回まではNSNotificationCenterを使った通知の説明だったと思うので、次にキー値監視(Key-Value Observing)(略はKVO)に行く。

調べてて物凄く混乱したりして、今も混乱中ではあるけど気にしない。
混乱していた最大の原因は、キー値コーディング(Key-Value Coding)(略はKVC)の知識なしにKVOを調べようとしていたこと。
KVCありきのKVOです。

で、キー値コーディングってどんなのってことになるけど、自分が現状理解している範囲で説明するとする。
プロパティとかインスタンス変数の扱い方で、それらの名前(文字列)をキーにして値の出し入れをできるようする手段。って感じのよう。
注意点は、アクセサがあればアクセサを経由で値を扱ってくれて、アクセサがなければないで勝手に値の出し入れをやってくれる。
キー値監視のサンプルコードなどを見てると、キー値監視用のプロパティに対するアクセサがあったりなかったりなので、自分混乱しまくりでした。

キー値監視については、指定したプロパティなどの値が変化したら通知してくれる。
キー値監視のサンプルコード見ててもう一つ混乱したのが、プロパティの値の変更はキー値コーディング的に行われてる場合と普通のセッター使って行われてる場合があるっぽいこと。


それと、一つ前の記事『非同期処理と通知とスレッドセーフ』でも書いたけど、バックグラウンド処理とキー値監視を組み合わせてる場合にはスレッドセーフかどうかを気にしましょう。
プロパティの値の変更(オブザーバへ通知)からオブザーバでの通知受取後の処理までの一連の処理は、通知元のスレッドIDで実行されてたりします。

疲れたのでサンプル載せて「キー値監視」のことはもう終わりにしちゃう。
ハッキリ言って、「キー値コーディング」「キー値監視」は奥が深そうです。
こんなわたしのブログ見るよりまともな参考書で勉強すべきだ、とういうのが今回の結論です。


ここで『「Cocoa Notification (NSNotification,NSNotificationCenter)」と「キー値監視」』について終わり。
混乱は収束しないです。


Xcode 3.2.4 and iOS SDK 4.1 で試してる。
古いバージョンとか新しいバージョンのこと考えてない。

新規プロジェクトをView-based Applicationを選択して名前をMyKvoとして作成してます。
新規ファイル追加で、NSObjectを継承したcreatureを作成しています。

// MyKvoViewController.h

#import <UIKit/UIKit.h>

@class creature;

@interface MyKvoViewController : UIViewController {
creature *human;
}

@property (nonatomic, retain) creature *human;

@end


// MyKvoViewController.m

#import "MyKvoViewController.h"
#import "creature.h"

@implementation MyKvoViewController

@synthesize human;

- (void)viewDidLoad {
[super viewDidLoad];

human = [[creature alloc] init];
human.sex = @"male";

// humanオブジェクトのcommentプロパティの値に変化があれば selfに通知されるようにする。
// ここではselfがオブザーバとなる。
[human addObserver:self forKeyPath:@"comment" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];

// いろいろな方法でhumanのcommentプロパティの値を変化させてみよう。
human.comment = @"I am a man.";
[human setComment:@"I'm a male."];
[human setValue:@"I'm not sure." forKey:@"comment"];
[human setIsHavingSausage:YES];
[human setIsHavingSausage:NO];

// commentのキー値変更のselfに対する通知を停止する。
// addObserver に対して removeObserver。使わなくなったキー値監視は消すように。
[human removeObserver:self forKeyPath:@"comment"];
human.comment = @"I am a man.";
}

/**
* ここで通知を受けとる
*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqual:@"comment"]) {
NSLog(@"通知受信 comment:%@", [(creature *)object comment]);
}
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
}

- (void)dealloc {
[human release];
[super dealloc];
}

@end


// creature.h

#import <Foundation/Foundation.h>

@interface creature : NSObject {
NSString *comment;
NSString *sex;
BOOL isHavingSausage;
}

@property (nonatomic, retain) NSString *comment;
@property (nonatomic, retain) NSString *sex;

- (void)setIsHavingSausage:(BOOL)isHavingSausage_;

@end


// creature.m

#import "creature.h"

@implementation creature

@synthesize comment;
@synthesize sex;

- (void)setIsHavingSausage:(BOOL)isHavingSausage_
{
if (isHavingSausage_ && [self.sex isEqualToString:@"male"]) {
self.comment = @"I am a real man.";
} else {
self.comment= @"I'm a woman!";
}

isHavingSausage = isHavingSausage_;
}

- (void)dealloc {
[comment release];
[sex release];
[super dealloc];
}

@end



続かない。

0 件のコメント:

コメントを投稿