Objective-Cを触ってみんとす。
iPhoneのSDKが公開されたので、とりあえず ObjectiveC の勉強をしてみんとする。
といっても、Macももってないし、iPhone SDK を入手するわけでもなく。
クラス定義
- クラスを定義するには、@interface と、@implementationが必要。
- @interfaceがクラスのインタフェースの宣言。
- @implementationが実装クラス。
- インスタンスメソッドは、"-" クラスメソッドは、"+"
- 自クラス内のメソッドを呼び出すときは、self
とりあえず、以下のとおりに、Pointクラスを作ってみた。
参考にしたのは、http://wisdom.sakura.ne.jp/programming/objc/objc4.html
の内容。
// Point.h #import <objc/Object.h> @interface Point : Object { // instance variables int x; int y; } - (void)x: (int)value; - (int)x; - (void)y: (int)value; - (int)y; - (void)x: (int)valueX y:(int)valueY; - (int)methodA; - (int)methodB; @end
// Point.m #import "Point.h" @implementation Point - (void)x: (int)x { self->x = x; } - (int)x { return x + 10; } - (void)y: (int)y { self->y = y; } - (int)y { return y; } - (void)x: (int)x y:(int)y { self->x = x; self->y = y; } - (int)methodA { return x + y; } - (int)methodB { return [self methodA] * 2; } @end
// PointMain.m #import <stdio.h> #import <objc/Object.h> #import "Point.h" int main() { id p1, p2; p1 = [Point alloc]; p2 = [Point alloc]; [p1 x:1 y:2]; [p2 x:3 y:4]; printf("p1 x:%d y:%d\n", [p1 x], [p1 y]); printf("p2 x:%d y:%d\n", [p2 x], [p2 y]); [p1 x: 102]; [p2 y: 500]; printf("p1 x:%d y:%d\n", [p1 x], [p1 y]); printf("p2 x:%d y:%d\n", [p2 x], [p2 y]); return 0; }
参考にしたサイトだと、アクセッサをsetPoint とか、getX とか定義していたんだけど、
set とか get とか個人的にいやなので、インスタンス変数と同じ名前で、アクセッサを用意してみた。
Objective-C界隈では、どんな慣習になっているのか分からないけど。
これを、実行すると、
>gcc -c -Wno-import Point.m >gcc -c -Wno-import PointMain.m >gcc -o Point Point.o PointMain.o -lobjc >Point.exe p1 x:1 y:2 p2 x:3 y:4 p1 x:102 y:2 p2 x:3 y:500
気になるのが、インスタンス変数の宣言が、@interface 側にあること。
インスタンス変数は実装に応じて用意するものだと思っているので、
@implementation側はわかるとして、@interface側はしっくりこない。
@interfaceは、実装もある程度規定するという意味なんだろうか。
Javaのinterfaceとは、考え方が違うものなのかな。。
継承
// SuperClass.h #import <objc/Object.h> @interface SuperClass : Object { int x; } -(void)methodA; -(void)methodC; -(void)methodD; @end // SuperClass.m #import "SuperClass.h" @implementation SuperClass -(void)methodA { printf("SuperClass methodA.\n"); } -(void)methodC { printf("SuperClass methodC.\n"); } -(void)methodD { printf("SuperClass methodD.\n"); } @end //SubClass.h #import "SuperClass.h" @interface SubClass : SuperClass -(void)methodB; -(void)methodC; -(void)methodD; @end //SubClass.m #import "SubClass.h" @implementation SubClass -(void)methodB { printf("SubClass methodB.\n"); } -(void)methodC { printf("SubClass methodC.\n"); } -(void)methodD { printf("SubClass methodD.\n"); [super methodD]; } @end //SuperClassMain.m #import <stdio.h> #import "SubClass.h" void callMethodC(id obj) { [obj methodC]; } int main() { id obj = [SubClass alloc]; [obj methodA]; [obj methodB]; [obj methodC]; callMethodC(obj); [obj methodD]; obj = [SuperClass alloc]; [obj methodA]; [obj methodC]; callMethodC(obj); return 0; }
実行すると、
> gcc -c -Wno-import SuperClass.m > gcc -c -Wno-import SubClass.m > gcc -c -Wno-import SuperClassMain.m > gcc -o SuperClass SuperClass.o SubClass.o SuperClassMain.o -lobjc > SuperClass SuperClass methodA. SubClass methodB. SubClass methodC. SubClass methodC. SubClass methodD. SuperClass methodD. SuperClass methodA. SuperClass methodC. SuperClass methodC.
なるほど、肝はcallMethodC関数の中。
コンストラクタ(イニシャライザ)
ひとつひとつかいてもしょうがないので。
- allocしたメモリは、freeメソッドで開放してあげないとならない。
- freeをオーバライドして、デストラクタとする。
- id型でなく、クラス型のポインタを使って、型をコンパイル時に判定できる。
- HogeClass *obj = [[HogeClass alloc] init]; [obj method];
- けど、所詮ポインタなので、実際はどのクラスでも代入可能。
- クラス変数はない。
- クラスのヘッダファイルの中に、ファイルスコープのグローバル変数を定義する。
- クラスもオブジェクト
- Class testClass = [Test class];
- [testClass Write];
- [[testClass new] free];
あしたはセレクタから。