スキップしてメイン コンテンツに移動

投稿

ラベル(ObjectiveC/Cococa)が付いた投稿を表示しています
今回は 『 Java言語で学ぶデザインパターン入門 』 からStrategyパターン。 特に解説なし。 HandクラスのコードがStaticを使用した形でそのままではObjective-Cでは移植しづらかったので、少し修正したがコード自体は汚い。 StrategySample.dmg

Objective-CでUnit Test

XCodeにはUnit TestのFrameworkであるSenTestingKitが添付されている。SenTestingKitでのテスト方法を簡単にまとめておく。 以下のようなクラス Circleがあった場合、 #import <Cocoa/Cocoa.h> #define PI (double) 3.14159 @interface Circle : NSObject { double _radius ; } +( id )circleWithRadius: ( double ) raidus; -( id )initWithRadius:( double )radius; -( double )diameter; -( double )dimension; -( double )circumference; @property ( readwrite ) double radius; @end まず、テスト用の新規ターゲットを作成する。このときアシスタントで「Cocoa」のカテゴリーから「Unit Test Budle」を選択しておく。名前は何でもよい"TestCircle"などとしておく。 次にFrameworkの取り込みを行う。 Frameworkの定義は、/Developer/Libary/Frameworks/SenTestingKit.frameworkにあるのでこれをプロジェクトに追加する。ここで、先に作成した新規ターゲット"TestCircle”に追加する。 そしていよいよテスト用のコードの追加。 新規ファイルをプロジェクトに作成し、ファイルの種類を「Objective-C test case class」を選択する。ヘッダーフィアルを見るとSenTestingKitのヘッダーのインポートとクラスのテンプレートができているので、ここにテストしたいクラスのインスタンスとテスト用のメソッドを定義しておく。 #import <SenTestingKit/SenTestingKit.h> #import "Circle.h" @interface CircleTest : SenTestCase { Circle * circle ; } ...

Objective-Cの手習い:Bridgeパターン

今回は 『 Java言語で学ぶデザインパターン入門 』 からBridgeパターン。 一応クラス図を載せておく。 ほとんど書くこともない。 今回もプロトコルを使うという手もあったが、普通のクラスにしてからメソッドを作って抽象クラスを表している。 コード見てくださいな。 Download Site

Objective-Cの手習い:AbstractFactoryパターン

今回は『 Java言語で学ぶデザインパターン入門 』からAbstractFactoryパターン。 クラス数が多いのでクラス図を示しておこう。 とりあえずAbstract Factoryとは…… 協調して働くセットのオブジェクトをまとめて作製するためのインターフェイスをプログラマーに提供するパターン。プログラマーは抽象クラスであるFactoryの具象クラスを何らかの方法で得て、その抽象的なインターフェイスを通じてセットのオブジェクトを生成する。 今回もほとんどそのままの移植で、Objective-Cらしいところはあまりない。 唯一Objective-Cに依存した部分は、Factoryクラスの具象クラス生成部。『 Java言語で学ぶデザインパターン入門 』ではJavaのClassクラスを使用して生成しているが、Objective-CではNSClassFromString関数を使用してClassクラスのインスタンスを生成し、そこからFactoryの具象クラスのインスタンスを生成する。 Factory* factory = nil; Class factoryClass; factoryClass = NSClassFromString(classname); if(!factoryClass) { return nil; } else { factory = [[[factoryClass alloc] init] autorelease]; return factory; } JavaのコードのようにExcetionを拾っていないので、呼び出し側で対処する必要がある。どうもObjective-CではExceptoinを積極的に使用していこうという思想ではないようだ。プログラマが考えよってことらしい。 今回はクラスが見つからない場合nilがかえるので呼び出し側では factory = [Factory factoryFromClassName:className]; if (...

Objective-Cのメモリー管理

最近はJavaをまずプログラム言語として始める人が多いだろうから、Objective-Cを使いだした際メモリー管理でつまずくことが多いだろう。わたし自身もすっかりJavaな人になっていたので同様に最初のころハマった。一応メモリー管理についてまとめておこう。 Objective-Cでは10.5からは今時の言語っぽくGabage Collectionが導入されので、Java同様あまりメモリー管理を気にする必要はなくなった。だが、パフォーマンスの問題からなのかXCodeのデフォルトの設定ではオフになっていたりするので、一応レガシィなメモリー管理のお手前も知っておこう。 リファレンスカウンタ、retain/release さすがに大昔のC++のようにnew/deleteで自身で管理ということはなくて、リファレンスカウンタという割と一般的な手法でメモリー管理はなされている。これはある変数について参照が増えるたびにカウントアップ、参照がなくなるごとにカウントダウンしていき、参照カウンタがゼロになった時点でオブジェクトが削除されるという管理方法。Objective-Cの場合、この仕組みが言語でなくCocoaのライブラリレベルで実現されている。 リファレンスカウンタは生成時点で1に、その後 retain メッセージを送るごとに一つ増え、 release するごとに減る。オブジェクトに retainCount というメッセージを送ると現在の参照カウンタを返してくれる。以下のようなコードでテストすると、 ObjectA* objA = [[ObjectA alloc] init]; ObjectA* obj_copy; NSMutableArray* array1 = [NSMutableArray array]; printf("After initializing : %i\n,[objA retainCount]); obj_copy = objA; printf("After assignment : %i\n,[objA retainCount]); [objA retain]; printf("After retain : ...

Objective-Cの手習い:Builderパターン

今回は『 Java言語で学ぶデザインパターン入門 』からBuilderパターン。 クラス数が多くなってきたのでクラス図を示しておこう。 今回のパターンのクライアントであるメインメソッドで、Directorクラスを生成する。このDirectorクラスを使いながら、抽象クラスであるBuilderクラスを通してTextBuilderとHTMLBuilderを利用する。Javaのサンプルではコマンドラインからの引数でどちらのBuilderを使用するかを決定するようになっているが、今回は両方を生成し実行するようにしている。TextBuilderのほうか結果をコンソールに、HTMLBuilderのほうはGreeting.htmlというファイルに結果のHTMLを書き出すようになっている。 今回の実装もほとんどJavaのサンプルコードそのまま。ただし、 getResult メソッドに関しては、Objective-CのProperty機能を使うことにした。 まず、抽象クラスであるBuilderクラスのヘッダーでの宣言を以下のようにする。 @property(readonly) NSString* result; 結果を戻すだけなので属性を readonly とし、結果は NSString で戻すこととした。戻す内容はTextBuilderとHTMLBuilderで異なるのでBuilderクラスでのImplementation部での宣言は @dynamic result; として、実行時に子クラスでオーバーライドされることを明示する。 TextBuilderでは result に結果のテキストそのもの返すため、結果を格納するNSStringのオブジェクト _buffer を定義し、     @synthesize result=_buffer; としてプロパティ result と関連付ける。これだけでTextBufferに result というメッセージを投げるとメソッドの定義なしで _buffer の内容を返してくれる。 HTMLBuilderでは結果については、 [_buffer writeToFile:_filename atomically:YES encoding:NSUTF8StringEncoding erro...

Objective-Cの手習い:Prototypeパターン

今回は『 Java言語で学ぶデザインパターン入門 』からPrototypeパターン。 ほとんどそのままの移植だが、ポイントは例ではJavaのjava.lang.Cloneableが使用されているが、Objective-CではFoundationに用意されているNSCopyingプロトコルを使用すること。 NSCopyingはオブジェクトのコピーする copy メソッドを実現しているプロトコルだ。NSObjectでも宣言されているが、内容は空なのでここではあらためて抽象クラスであるProductクラスでも宣言しておく。このプロトコルを実装するには copyWithZone を実装すればよい。ここでは子クラスに依るので、Productクラスでは内容は空。実際のProductクラスの実装クラスのMessageboxクラスでは以下のような実装となる。 -(id)copyWithZone:(NSZone*)zone { id copyDestination = [[[self class] allocWithZone:zone] initWithChar:decochar]; return copyDestination; } 今回のクラスはインスタンス変数もプリミティブなintの変数を一つ持っているだけなのでこの程度でOk。『 Java言語で学ぶデザインパターン入門 』では専用の createClone というメソッドを定義しているが、ここでは素直に copy を使うことにする。 オブジェクトのコピーやNSCopyingについては、Appleの『Memory Management Programming Guide for Cocoa』の" Implementing ObjectCopy "に詳しい解説がある。

Objective-Cの手習い:Singletonパターン

今回は『 Java言語で学ぶデザインパターン入門 』からSingltonパターン。 至って簡単なプログラムだが、Objective-Cでの注意点は3つ。 クラス変数がないこと メソッドの可視性を設定できないこと 決まった形式でのコンストラクタのようなものがないこと Javaなどではクラス変数にSingletonインスタンスを納めておくのが通常だが、Objective-Cではスタティック変数を用意して格納しておくことにする。@implementaion部の最初に以下のように宣言する。 static Singleton* s_singleton = nil; また、2と3の問題からJavaのようにコンストラクタをプライベートにして生成を制御するということができない。 で、NSObjectから継承された新たにインスタンスを作成しそうな基本メソッドをまずオーバーライドしていく。具体的には allocWithZone / copyWithZone などがそれにあたる。また解放に関する部分も勝手に解放されてはまずいので手を入れておく( retain / retainCount / release / autorelease など)。 具体的にはSingletonクラスの基本メソッドのオーバーライド部分は以下のようになる。 +(id)allocWithZone:(NSZone*)zone { @synchronized(self) { if(!s_singleton) { s_singleton = [super allocWithZone:zone]; } } //アップルのガイドでは最初はインスタンスを返し以降はnilを返すことに //なっているが、それだとうまくいかないので以下のように常にインスタンス //を返すように変更 return s_singleton; } -(id)copyWithZone:(NSZone*)zone { return self; } -(id)retain { return self; } -(unsigned)retainCount; { //解放できないオブジェクトであることを示す...

Objective-Cの手習い:TemplateMethodパターン

今回はTemplateMethodパターン。 『 Java言語で学ぶデザインパターン入門 』をベースにしているので、コードの意味などはこちらのJava版のソースコードを参照ください。 まずは素直にJavaのコードを移植したパターン(TemplateMethod1)。 Objective-Cには言語として抽象クラスのサポートがない。概念なのでプログラマーが勝手にやれよということらしい。で、サンプルコードでは AbstractDisplay という名前になっているが実際にはサブクラスで実装を期待するメソッドについては空メソッドを定義している。 -(void) open { } -(void) print{ } -(void) close{ } 呼び出す側のメイン関数も以下の通り char c = 'H'; id d1 = [[CharDisplay alloc] initWithChar: c]; id d2 = [[StringDisplay alloc] initWithString:@"Hello World!"]; AbstractDisplay* d3 = [[StringDisplay alloc] initWithString:@"日本語でこんにちは"]; [d1 display]; [d2 display]; [d3 display]; 結果は以下のようになる。 <<HHHHH>> +------------+ |Hello World!| |Hello World!| |Hello World!| |Hello World!| |Hello World!| +------------+ +------------------+ |日本語でこんにちは| |日本語でこんにちは| |日本語でこんにちは| |日本語でこんにちは| |日本語でこんにちは| +------------------+ これだけでは面白くないの...

Objective-Cの手習い:Adapterパターン

今度は、また『 Java言語で学ぶデザインパターン入門 』からAdapterパターン。 Wrapperとも呼ばれるように、別クラスを被せるようにデザインしてインターフェイスを替えてあげるもの。Adapterを実現する方法として 継承を利用する方法 委譲を利用する方法 がある。Objectivel-Cでは、他の言語と同様に前者については継承と Protocol (Javaでいう Interface )を利用して実現、後者については Protocol とインスタンス変数として Banner を持つことで実現できる。 一般的にはC++のような静的な型付けが強い言語では前者、Smalltalkのような動的な言語では後者が採用されるケースが多い。今回は後者のパターンで書いてみる。 ただし、Objetive-Cではカテゴリという機構があるので後者をより簡易に実現できる非形式 Protocol が利用される。これは、オリジナルのクラス自体を拡張させて新たなインターフェイスを持たせることができるもの。 Banner クラスはそのままJavaのコードを移植して以下のような宣言になる。 Banner.h @interface Banner : NSObject { NSString* i_string; } -(id)initWithString:(NSString*) strg; -(void)showWithParen; -(void)showWithAster; @end 今回は、非公式 Protocol を利用する。これは、Objective-Cのカテゴリの機能を使ったもの。宣言部は以下のようになる。 Banner+Print.h @interface Banner(Print) -(void) printWeek; -(void) printStrong; @end カテゴリとはObjective-Cらしいところで、既存のクラス(この場合、 Banner クラス)に新たなメソッドを動的に追加できるのだ。「動的」とは、 Banner クラスのソースコードをなくオジェクトモジュールしかない場合も、Objective-Cではこの機構を新しいメソッドを Banner クラスに追加していけるということ。 またこの機構を使った場合の、ソースの...

Cocoa/Objective-Cの手習い

Objective-Cをちゃんと勉強して来なかったので、ここらでちゃんと勉強しようかと思いたった。まずは手習いとして、結城浩氏の『 Java言語で学ぶデザインパターン入門 』の各パターンでも移植してみよう。コード自体の意味や内容についてはそちらを参照してほしい。 第一回は Iterator パターン。 Objective-CではFoundationに Iterator を実装した NSEnumerator が提供されているが、敢て実装してみる。 Objective-C自身は、オブジェクト指向の部分はC++などと違ってSmalltalkに近く、純粋に「らしい」コードを追求すればもっとよいコードがあるだろう。まず、JavaでいうInterfaceのようなものはないし、動的な指向が強く全てのオブジェクトが NSObject というクラスに辿れるので本当はもう少し柔軟なコードが簡単に書けそうな気がする。が、ここは手習いなのでJavaのコードに準じたコードにしてみた。 まず、Javaのインターフェイスとして定義されている Iterator と Aggregate はObjective-Cでは少し異端とも思える静的な型付けを意識した Protocol を用いて以下のようなコードとする。 Iterator.h @protocol Iterator -(BOOL)hasNext; -(id)next; @end Aggregate.h @protocol Aggregate -(id <Iterator>)iterator; @end これら抽象クラスの実体として BookShelfIterator と BookShelf を用意する。それぞれの宣言は以下の通り BookShelfIterator.h @interface BookShelfIterator : NSObject <Iterator> { BookShelf* bookShelf; int index; } -(id)initWithBookShelf:(BookShelf*)shelf; @end Aggregate の中での集合の扱いは ...

XCode 3.0

いまさらながら、XCode 3.0に移行してみた。 Interface Builderがかなり所作が変わっていて、結構戸惑ったので書きのこしておこう。 以前はInterface Builder上のインスペクタでClassを作成して、Instance化して、GUIパーツとOutletやActionをドラッグで結ぶというやり方だった。今回の変更でインスペクタ上でClassとかInstanceとかが無くなっていたので一瞬呆然としてしまった。今までと全く異なる右のようなインターフェイスになってしまったからだ。 例えば、いままで通りMVCのControllerにあたるクラスを作りたい時、正解はインスペクタからCocoaのObject & Controllersの中からObjectをドラッグしてきて右のように置く。そしてId Inspectorを開いて、Class ActionsとClass Outletsに必要なものを追加していく。今回はよくCocoaの入門本にあるようにAppContollerという名前で作ってみた。 Action/Outletの関連付けも以前と作法が違っている。AppContollerを選択してContol + クリックすると右のようなパネルが開かれる。Outlet/Actionの右の○をクリックしてドラッグすると青い線が伸びていくので、それを該当のパーツに繋げると関連付けができる。 次に、Interface BuilderのFileメニューからWrite with Classを選んでクラスファイルを生成してしまう。このとき、自動的にプロジェクトに追加されても良さそうなものだがデフォルトでは追加されないようだ(やり方がマズいのか?)。 プロジェクトで、Classesのグループ上でControl + クリックで「追加」を選び、「既存のファイルの追加」を行なう。 次にクラスファイルのヘッダーファイルを開くと、今までのやり方と違いこの手順では親クラスが特定できていないので生成されたコードは以下のように「親クラスを特定せい!」というコメントが入って親クラスが指定されていない。ここでコメントを消してNSObjectを親クラスに明示的に指定してあげる。 実装のほう(ApplContoller.m)を見てみると、Im...