メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2012年6月23日土曜日

[Objective-C][お勉強][メモ]クラス定義

クラスは以下の2つに分けて定義する。

1) インタフェース
2) 実装

通常インタフェースと実装は別々のファイルとし、インタフェースは.h、実装は.mという拡張子をもつ。


インタフェース
インタフェースはディレクティブ@interfaceで始まり、ディレクティブ @endで終わる。
クラスのインタフェースは以下のように定義する。

@interface クラス名 : スーパクラス
{
  インスタンス宣言
}
メソッド宣言
プロパティ宣言
@end









メソッド宣言
クラスメソッド
先頭に"+"(プラス)をつける。
戻り値の型はC言語の型キャストの構文を使って記述する。
戻り値やパラメータの型を省略すると、デフォルトでidが使用される。
パラメータはメッセージと同様に名前の後のコロンの後に記述する。
+ (戻り値の型)メソッド名;
+(戻り値の型)メソッド名:(パラメータの型)パラメータ;
+(戻り値の型)メソッド名:(パラメータの型)パラメータ 名前:(パラメータの型)パラメータ;

インスタンスメソッド
先頭に"-"(マイナス)をつける。
戻り値の型はC言語の型キャストの構文を使って記述する。
戻り値やパラメータの型を省略すると、デフォルトでidが使用される。
パラメータはメッセージと同様に名前の後のコロンの後に記述する。
-(戻り値の型)メソッド名;
-(戻り値の型)メソッド名:(パラメータの型)パラメータ;
-(戻り値の型)メソッド名:(パラメータの型)パラメータ 名前:(パラメータの型)パラメータ;



可変パラメータをもつメソッド
Cと同様にカンマと省略記号を使って宣言する。
- (void)methoddayo:param1, ...;




プロパティ宣言
プロパティ宣言は以下のように記述する。
@property (attribute) Type propertyName;





インスタンス宣言
もともと必要だったが、今や実装ブロックやプロパティからの自動生成が可能なため、
通常はここでインスタンス宣言すべきでない、とのこと。
(波括弧も不要)


.



[Objective-C][お勉強][メモ]ソース上のクラス名

クラス名は以下の2つの場合にのみ使用できる。


1) 型名として使う場合

ObjA *objA;

等。

2) メッセージ式のレシーバとして使う場合
この場合のクラス名はクラスオブジェクトを意味する。

[ObjA alloc];

などなど。


また、クラス名はグローバル変数とネームスペースが同一のため、
同じ名前をつけることはできない。


.

[Objective-C][お勉強][メモ] ルートクラスのメソッド

クラスオブジェクトはルートクラスのインスタンスメソッドを実行する権限があるらしい。

.

[Objective-C][お勉強][メモ] クラスオブジェクトの初期化

クラスが静的変数やグローバル変数を使っている場合、initializeというメソッドで初期化するのが良いんでないかい、と書いてある。


ランタイムがinitializeメッセージを送るタイミングは以下のとおり。

1) メッセージを受信する前
2) 該当クラスのスーパークラスがinitializeメッセージを受信した後

よって、クラスは使用される前にinitializeメッセージを処理する機会が与えられる。

特に初期化する必要がなければ、initializeメソッドを実装する必要は無い。


注意点!
initializeを実装したスーパークラスObjAを継承したinitializeを実装しないクラスObjBがある場合、ObjBに対して送られたinitializeメッセージはObjBに該当するinitializeメソッドが
無いため、スーパークラスObjAのinitializeへと転送する。そのため、ObjAのinitializeメソッドが複数回実行されてしまう場合がある。

複数回実行されるのを防ぐために、以下のように実装する。

+(void)initialize
{
  if (self == [ObjA class]) {
    // ここで初期化処理
  }
}


とのこと。

2012年6月22日金曜日

[Objective-C][お勉強][メモ] クラス変数

そんなものは無い。



グローバル変数やstatic変数で代用した例。
static ObjA *objA;

@implementation ObjA;
+(id)getInstance
{
  どーのこーのどーのこーの
  return objA;
}

もちろん

static ObjA *objA;

じゃなく、

ObjA *objA;

とすることも可能。
だけど、なるべく有効範囲を限定した方が有効、とのこと。

.

[Objective-C][お勉強][メモ] インスタンス作成

allocメソッド
新しいオブジェクトのインスタンス変数を動的にメモリを割り当てる。
割り当てたインスタンス変数を0に初期化する。
クラスオブジェクトには少なくともallocのようなメソッドが1つ以上ある。

id str = [NSString alloc];

みたいな。


initメソッド
オブジェクトが有用であるためには、0で初期化するだけじゃなく
完全に初期化する必要があり、その初期化を行う。
通常allocの直後に行う。
クラスオブジェクトには少なくともinitのようなメソッドが1つ以上ある。

id str = [[NSString alloc] init];

とか。

[Objective-C][お勉強][メモ] クラスオブジェクト

ソースコード上では、クラスオブジェクトはクラス名として表される。
ex)
[NSString alloc];

メッセージ式で、単なるレシーバオブジェクトとして表される。
その他の場合、クラスまたはインスタンスに対してidクラスを返すよう要求することで
クラスオブジェクトを得られる。
ex)
id classObjDaYo = [NSString class];

NSString *strObj = [NSString @"aaa"];
id classObj2DaYo = [strObj class];

上記で、クラスオブジェクトはid型としているが、すべてのクラスオブジェクトは
Class型なので、Class型とすることもできる。
ex)
Class classObjDaYo = [NSString class];

.

[Objective-C][お勉強][メモ] 型のイントロスペクション

実行時にインスタンスがどの型かを調べることができる。
調べるためには、NSObjectのメソッドが使える。

isMemberOfClass:
レシーバが、引数で指定されたクラスであるかどうか調べる。

[objA isMemberOfClass:ObjA];

objAはObjAクラスであるかどうか。


isKindOfClass:
レシーバが、引数で指定されたクラスを継承しているか、または属しているかを調べる。

.

[Objective-C][お勉強][メモ] 継承

クラス定義は追加的に定義する。

新しいクラスはすべて別のクラスをベースとする。


NSObjecgt
ルートクラスは普通はNSObject。
NSObjectはルートクラスなのでスーパクラスが無い。
ルートクラスを定義することも可能だけど、止めといた方がいいってさ。
オブジェクトとして動作させるコードが書いてあるらしい。

インスタンス変数
普通に継承

メソッド
普通

メソッドのオーバライド
普通.

インスタンス変数のオーバライド
できない。

抽象クラス
継承されることが目的であったり、主に継承されることが目的のクラス。
通常、単独では不完全。
ただし、Objective-Cにはクラスを抽象クラスとしてマークするような構文は無い。
抽象クラスであってもallocできる。




2012年6月21日木曜日

[Objective-C][お勉強][メモ] クラス

Objective-Cではクラスを定義することでオブジェクトを定義する。

クラスの定義は一種のオブジェクトのプロトタイプ。

コンパイラによってクラスに1つだけアクセス可能な「クラスオブジェクト」(ファクトリオブジェクト)が作成される。
このクラスオブジェクトにより構築されるオブジェクトが、クラスのインスタンス。


慣習的にクラス名は大文字で始まる。
インスタンス名は小文字で始まる。

.

[Objective-C][お勉強][メモ] ドット構文

アクセサメソッドを呼び出す[]の代わりにドットを使うことができる。
直接インスタンス変数を変更しているわけではなく、アクセサメソッド呼び出しの「構文糖」。

[ObjA setValue:10];

と書く代わりに

ObjA.value = 10;

と書くことができる。
同様に

int a = [ObjA getValue];

と書く代わりに

int a = ObjA.value;

と書くことができる。

直接ObjAのインスタンス変数valueにアクセスしているわけではなく、
ObjAのアクセサメソッドを経由している。

自分の保有するインスタンス変数にアクセスする場合、self.(selfドット)をつけて
アクセスすれば、アクセサメソッド経由になる。もちろんself.を付けなければ
直接インスタンス変数にアクセスする。

[self setValue:10];



self.value = 10;

と同等だけど、

value = 10;

とは違う。インスタンス変数に直接アクセスしている。


へへ。
.

[Objective-C][お勉強][メモ] 動的バインディング

受信側のオブジェクトと、メッセージは、メッセージが送信されるまで結合されない。

なので、実際にどのメソッドが実行されるかは、実行時にだけ知ることができる。


さらに、送信するメッセージ(メソッドセレクタ)も実行時に決定させることが可能。
(メッセージ(メソッドセレクタ)を変数にする)

.

[Objective-C][お勉強][メモ] ポリモーフィズム

異なるオブジェクトでも同じセレクタ名を持つのであれば
同じメッセージに対して、応答することができる。

@implementation ObjBase;
- (void)methodBase:(id)obj
{
  [obj methodYahoo];
}
@implementation ObjA;
- (void)methodYahoo
{
  NSLog(@"ObjA DA YO!");
}
@implementation ObjB;
- (void)methodYahoo
{
  NSLog(@"ObjB DA YO!");
}

であれば、

[[[ObjBase alloc] init] methodBase:[[ObjA alloc] init]];

がいけるとすれば、

[[[ObjBase alloc] init] methodBase:[[ObjB alloc] init]];

もいけるって感じかどうなのか。
.

[Objective-C][お勉強][メモ] オブジェクトメッセージング

あるオブジェクトに対して何か実行させたいなら、そのオブジェクトに対してメッセージを送るんだそうだ。
その書式は以下。

[receiver message];

これを「メッセージ式」というらしい。

receiver は、メッセージを受信するオブジェクト。
messageは、receiverが実行すべきこと。



ランタイムシステムはメッセージが送信されると、receiverの持つ全てのメソッドの中から適切なメソッドを選んで呼び出す。

なので、message部分はreceiverのメソッド実装を「選択」することから
セレクタと呼ぶこともあるとのこと。

message部の書き方
AオブジェクトのBメソッドを実行する場合
[A B];

Aオブジェクトの引数1つのBメソッドを実行する場合
メソッド名の直後にコロンを置いて、その直後に引数の値を指定する。
[A B:10];

Aオブジェクトの複数の引数を持つBメソッドを実行する場合
2つ目以降の引数には引数名とコロン、そして引数の値を指定する。
[A B:10 C:20 D:30];

セレクタ名(Javaで言えばシグネチャ?)は、メソッド名とパラメータ名で成る。
上記の例だと
B:C:D:
となるとのこと。コロンが3つあるのは引数を3つ取るため。
戻り値や引数の型はセレクタ名には含まれない。

Aオブジェクトの可変引数を持つBメソッドを実行する場合
コロンの後にカンマで区切って指定する。
[A B:10,20,30];

セレクタ名にはカンマは含まれない。
なので[A B:10,20,30]のセレクタ名は
B:
となる。

値を返すメッセージ式
メッセージ式で指定されたメソッドが値を返す場合、メッセージ式は値を返すことができる。
A = [B C];

BオブジェクトのCメソッドを実行した結果、その戻り値をAに代入。

 メッセージ式の中にメッセージ式
メッセージ式はネストできるので以下のように書くことができる。
[A B:[C D]];

上記は、CオブジェクトのDメソッドの戻り値をAオブジェクトのBメソッドのパラメータとしている。


nilへのメッセージ
nilへメッセージ送信可能。

nilへのメッセージパターン
1) メソッドがオブジェクトを返す場合、nilを返す。

ObjB *objB = nil;
ObjA *objA = [ObjB methodReturnsObjA];

の場合objAはnil。


2) メソッドが以下の型を返す場合、メソッドは0を返す。
ポインタ型、sizeof(void*)以下のサイズの整数スカラ、float、double、long double、long long

@implementation ObjA;
- (float)methodReturnsFloat;

の場合、

ObjA *objA = nil;
[objA methodReturnsFloat];

は、0.0を返す。

3) メソッドがstructを返す場合は、そのstructのすべてのフィールドに0.0を返す。

4) 上記、1)〜3)以外の場合は、返す値は不定。


そんだけ。
.

2012年6月20日水曜日

[Objective-C][お勉強][メモ] 動的型定義

オブジェクトは実行時に動的に型定義されるらしい。

どうやって型を特定するかというと、

振る舞い(メソッド)とデータ(インスタンス変数)の種類

で特定するっぽい。


で、これはisa変数ってのがやるみたい。

.



[Objective-C][お勉強][メモ] nil

NULLみたいなものでnilっていうのがある。

NULLオブジェクトだそうで。


値が0のid。


.

[Objective-C][お勉強][メモ] id

どんなオブジェクトにも対応する汎用的な型に


id

という型がある。なんだかよく分からないけど、デフォルトのデータ型らしい。


typedef struct objc_object {
  Class isa;
} *id;

だそうで。

なので、idはstruct objc_objectへのポインタ。

isaっていうのは、このオブジェクトがどのクラスのインスタンスかを
表すobjc_classへのポインタ。

.

[Objective-C][お勉強][メモ] メモリ管理

Objective-Cがサポートしているメモリ管理の仕組みは

1) 自動参照カウント(ARC:Automatic Reference Counting)
2) 非自動参照カウント(MRC:Manual Reference Counting/MRR:Manual Retain/Releae)
3) ガべージコレクション

の3つ。3)はiOSでは非対応。


1) 自動参照カウント(ARC)
コンパイラが勝手にオブジェクトの存続期間を推論しちゃって決定する。

2) 非自動参照カウント(MRC)
オブジェクトの存続期間は人間(ディベロッパ)が管理する。

3) ガベージコレクション
自動コレクタというのが勝手にオブジェクトの存続期間を管理する。


らしいよ。
.