ここでは,Stanford 大学での授業で課された宿題(assignment)を解説します.一部アレンジしたものもあります.ぜひ自分でやってみてください.資料は英語ですが,内容は十分に理解できると思います.質問があれば TA か小嶋までどうぞ.
プログラムを書かないでアプリを開発します.右図のような画面を表示するだけのシンプルなアプリです.
- Xcode で Window-based Application を新規作成します.名前はたとえば HelloMYU としましょう.
- Resources から MainWindow.xib を開いて,Interface Builder を起動します.Tools > Library を開き,Label と Image View を Window にドラッグして配置します.
- Tools > Inspector で Label の Text 属性を「宮城大学へようこそ」にし,Font 属性などを調節します.大きさや位置を適当に調整してください.
- 宮城大学のシンボルマークの画像ファイルをダウンロードして,そのファイルを Resources にドロップしてください.(ドロップしたときのダイアログで "Copy ..." のチェックを入れるとよいです)
- Image View の属性 Image に,この画像ファイルを指定します.また Mode 属性を Aspect Fit に,Background 属性をWhite に設定します.Image View の大きさや位置を適当に調整してください.
- Interface Builder での変更を有効にするために File > Save します.
- Xcode のウィンドウに戻り,Build and Run を実行します.iPhone Simulator が起動し,右のような画面が出るはずです.
Mac OS X の上で動作するコンソールアプリです.Objective-C や Foundation の使い方に慣れることが目的です.ここでは,その手がかりだけをヒントとして解説します.Stanford 大学の資料に沿ってプログラミングを進めてください.
- Xcode で Mac OS X の Application を Command Line Tool(Type は Foundation)として新規作成します.名前はたとえば Assignment1b としましょう.
- Assignment1b.c を開くと main という関数が用意されています.これを Stanford の資料に沿って書き換えていきます.
- たとえば NSString についての情報を調べたいときは,Xcode > Help > Developer Documentation を開き,右上の検索窓に NSString と入れてください."Working with Paths" についての情報は,左側にある目次メニューから Task を展開し,該当する項目をクリックします.さらに調べたい項目(たとえば stringByExpandingTildeInPath)をクリックすれば,その詳細情報が得られます.
- プログラムを実行するには,Xcode > Run > Console を開き,そこで "Build and Run" をクリックしてください.NSLog の出力は,この Console に出力されます.
(ヒント)Section 1(ホームフォルダへのパスを表示)と Section 2(プロセス情報の表示)は,およそ次のようなプログラムになります.赤字は書き加えた部分です.他の Section についても,Developer Documentation を参考にしながら,Stanford 大学の資料に沿って,プログラムを作成してください.
#import <Foundation/Foundation.h> void PrintPathInfo () { NSString *path = @"~/"; NSString *full = [path stringByExpandingTildeInPath]; NSLog(@"My home folder is at '%@'", full); // This is not a perfect answer... NSArray *array = [full pathComponents]; for (int i = 0; i < [array count]; i++) { NSLog(@"%d: %@", i, [array objectAtIndex:i]); } } void PrintProcessInfo () { NSProcessInfo *pinfo = [NSProcessInfo processInfo]; int pid = [pinfo processIdentifier]; NSLog(@"Process ID is %d", pid); } int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; PrintPathInfo(); // Section 1 PrintProcessInfo(); // Section 2 //PrintBookmarkInfo(); // Section 3 //PrintIntrospectionInfo(); // Section 4 [pool drain]; return 0; }
1B の続きです.新しいクラス(PolygonShape)をつくることにチャレンジします.完成した 1B のプロジェクトを開き,そこに新しい機能を加えていきます.
- File > New File... を選択し,Mac OS X > Cocoa > Objective-C class を開きます.名前は PolygonShape.m としましょう.ヘッダファイルも同時生成するようにチェックを入れておきます.このクラスは,正多角形の形状を扱うためのものです.
- Stanford 大学の資料の Section 5 に沿って,プログラミングを進めてください.
- PolygonShape クラスを書いたら,まずは Assignment1b のプロジェクトをビルドし,文法エラーなどがないかチェックしてください.
- エラーがなければ,つぎに Assignment1b.m を書き換え,Section 6 の説明に沿って,プログラミングを進めてください.その核心部分は,およそつぎのようになります.
// Section 6 NSMutableArray *mar = [[NSMutableArray alloc] init]; PolygonShape *ps1 = [[PolygonShape alloc] init], *ps2 = [[PolygonShape alloc] init], *ps3 = [[PolygonShape alloc] init]; [ps1 initWith...]; [mar addObject:ps1]; [ps2 initWith...]; [mar addObject:ps2]; [ps3 initWith...]; [mar addObject:ps3]; NSEnumerator *enu = [mar objectEnumerator]; PolygonShape *ps; while (ps = [enu nextObject]) [ps setNumberOfSides:10]; [ps1 release]; [ps2 release]; [ps3 release]; [mar release];
なお配列要素へのアクセスは,NSEnumerator を使わずに,for 文で配列の添字(0, 1, ..., [mar count])をスキャンすることでも可能です.
ヒントとして,PolygonShape.h のすべてと PolygonShape.m の骨格部分を書いておきます.参考にしてください.なお,angleInDegrees は頂点内角の角度を返します.
#import <Cocoa/Cocoa.h> @interface PolygonShape : NSObject { int numberOfSides; int minimumNumberOfSides, maximumNumberOfSides; } @property int numberOfSides; @property int minimumNumberOfSides; @property int maximumNumberOfSides; @property (readonly) float angleInDegrees; @property (readonly) float angleInRadians; @property (readonly) NSString *name; - (id)initWithNumberOfSides:(int)num minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max; - (id)init; - (void)dealloc; - (NSString *)description; @end
#import "PolygonShape.h" @implementation PolygonShape @synthesize numberOfSides; @synthesize minimumNumberOfSides; @synthesize maximumNumberOfSides; - (id)initWithNumberOfSides:(int)num minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max { if (self = [super init]) { self.minimumNumberOfSides = min; self.maximumNumberOfSides = max; self.numberOfSides = num; } return self; } - (id)init { return [self initWithNumberOfSides:5 minimumNumberOfSides:3 maximumNumberOfSides:10 ]; } - (void)dealloc { NSLog(@"A PolygonShape is going to be deallocated"); [super dealloc]; } // Implement the following methods yourself! - (void)setNumberOfSides:(int)num {...省略...} - (void)setMinimumNumberOfSides:(int)min {...省略...} - (void)setMaximumNumberOfSides:(int)max {...省略...} - (void)setNumberOfSides:(int)num {...省略...} - (float)angleInDegrees {...省略...} - (float)angleInRadians {...省略...} - (NSString *)name {...省略...} - (NSString *)description {...省略...} @end
「2A. WhatATool (Part II)」の結果をふまえて,MVC(Model-View-Controller)デザインパターンにもとづく iPhone アプリに仕立てます.またグラフィック出力はありませんが,MVC の考え方を実践に結びつけてください.Stanford 大学の資料のとおり,Controller.h/.m を IB 上で自動生成してもよいですが,ここでは Xcode 上で書いていく方法を紹介します.
- Xcode > iPhone OS > Application > Window-based Application を新規作成します.名前は HelloPoly でよいでしょう.
- M をつくる:2A で作成した PolygonShape.h/.m を採り入れます.Xcode の Classes フォルダを右クリックして,Add > Existing Files... を選択し,PolygonShape.h/.m の両方を "Add" します.PolygonShape.h にある #import <Cocoa/Cocoa.h> を #import <Foundation/Foundation.h> に書き換えてください.
- V をつくる:IB 上で右図のようなユーザインタフェースをつくります.ラベルが1つとボタンが2だけのシンプルなインタフェースです.
- C をつくる:新しいクラス Controller.h/.m を作ります.Xcode > File > New File > Cocoa Touch Class > Objective-C class を選択し,ヘッダファイルとともに新規作成します.
- Controller.h には,ラベルやボタンへの IBOutlet をインスタンス変数として宣言し,ボタンが押されたときの IBAction(-increase, -decrease)も宣言しておきます.これに加えて,#import "PolygonShape.h" を加え,インスタンス変数に PolygonShape *polygonShape; を加えておきます.
- Controller.m には,-increase と -decrease の実装に加えて,-awakeFromNib の中で polygonShape オブジェクトを生成するようにします.いずれのメソッドについても,インタフェース(辺の数)を更新するようにしてください.(-updateInterface というメソッドを作って,それを [self updateInterface]; のように呼び出すとよいでしょう.)
ここでは HelloPoly のグラフィック出力を実現します.5回目の道場「Views, Drawing, and Animation」で詳しく取り上げますので,Stanford 大学の資料と併せて,参考にしてください.ここではヒントだけをお伝えします.
- IB で UIView を Window にドラッグし,たとえば 280×280 の正方形に整え,多角形の描画オブジェクトとします.これを PolygonView というクラスのオブジェクトとして設定します,親クラスは UIView です.このオブジェクトを選択した状態で File > Write Class Files... を選択し,PolygonView.h/.m を自動生成します.
- Xcode に戻って Classes にこれらを入れてください.Controller.h に IBOutlet PolygonView *polygonView; のようにインスタンス変数を加えます.これが Controller から見える PolygonView オブジェクトです.
- IB で描画オブジェクトを Controller の polygonView に接続します.これで Controller から polygonView を制御できるようになります.
- polygonView.m の -drawRect を実装します.実際に多角形を描画するプログラムです.具体的には,(1) コンテクストを設定,(2) 必要ならば背景の塗りつぶし,(3) 最初の頂点からパスを開始,(4) 各頂点にパスを接続,(5) パスを閉じ,(6) 好きな色で Fill/Stroke となります.
- 多角形の名前("heptagon" など)は,UILabel を使って表示すると簡単です.Controller から「多角形の辺の数」の表示と連動して [polygonShape name] を表示させればよいでしょう.