Entries

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

C++から見たObjective-C - キー値監視

タグ: Objective-C C++ Boost

MVCを綺麗に実現するための仕組み。
KVC(Key-Value Coding――キー値コーディング)に準拠するModelに変更が生じたとき、それをViewやControllerに知らせる。
原語はKVO(Key-Value Observing)。

この仕組みがフレームワークで用意されているのは嬉しい。
ModelクラスはC++のクラスにしようかと考えていたが、これがあるならObjective-Cのクラスにした方が良さそうだ。

#import <Foundation/Foundation.h>

// Model

@interface Model : NSObject
{
	int value;
};

- (id)init;

@property int value;

@end

@implementation Model

@synthesize value;

- (id)init
{
	if(self = [super init])
	{
		value = 0;
	}
	return self;
}

@end

// View

@interface View : NSObject
{
	Model* model;
}

- (id)initWithModel:(Model*)targetModel;

@end

@implementation View

- (id)initWithModel:(Model*)targetModel
{
	if(self = [super init])
	{
		model = [targetModel retain];
		
		[model addObserver:self
		        forKeyPath:@"value"
		           options:NSKeyValueObservingOptionNew
		           context:NULL];
	}
	
	return self;
}

- (void)dealloc
{
	[model removeObserver:self forKeyPath:@"value"];
	[model release];
	[super dealloc];
}

- (void)observeValueForKeyPath:(NSString*)keyPath
                      ofObject:(id)object
                        change:(NSDictionary*)change
                       context:(void*)context
{
	NSLog(@"%@", [change objectForKey:NSKeyValueChangeNewKey]);
}

@end

// main

int main (int, const char*)
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	Model* model = [[[Model alloc] init] autorelease];
	View* view = [[[View alloc] initWithModel:model] autorelease];
	
	model.value = 10;
	model.value = 201;

    [pool drain];
	
    return 0;
}

似たようなことをC++(+Boost)でやってみる。

#include <iostream>
#include <boost/signals.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>

// Model

class Model : boost::noncopyable
{
public:
	Model() :
	val(0)
	{
	}
	
	void value(int n)
	{
		if(n != val)
		{
			val = n;
			value_change_event(this, n);
		}
	}
	
	int value() const
	{
		return val;
	}
	
	template <typename Slot>
	boost::signals::connection connect_value_slot(Slot slot)
	{
		return value_change_event.connect(slot);
	}
	
private:
	int val;
	boost::signal<void (Model*, int)> value_change_event;
};

// View

class View : boost::noncopyable
{
public:
	View(const boost::shared_ptr<Model>& target_model) :
	model(target_model)
	{
		if(model)
		{
			value_slot_connection =
				model->connect_value_slot(
					boost::bind(&View::display_value, _2)
				);
		}
	}
	
private:
	static void display_value(int val)
	{
		std::cout << val << std::endl;
	}
	
	boost::shared_ptr<Model> model;
	boost::signals::scoped_connection value_slot_connection;
};

// main

int main (int, const char*)
{
	const boost::shared_ptr<Model> model(new Model);
	View view(model);
		
	model->value(10);
	model->value(201);
	
    return 0;
}

流石にModelクラスの楽さは段違い。

スポンサーサイト

コメント

コメントの投稿

コメントの投稿
管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://idlysphere.blog66.fc2.com/tb.php/126-aec41de7
この記事にトラックバックする(FC2ブログユーザー)

Appendix

タグ

Blog内検索

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。