CHAPTER08 Foundationフレームワークの重要なクラス
2011/09/14(水) 17:44 Objective-Cはてブ情報 はてブに登録 はてブ数

immutableなオブジェクトとmutableなオブジェクト

可変なオブジェクト、不変なオブジェクトが存在するのは、
不変なオブジェクトはデータ構造が簡潔であり処理も軽くなります。
可変なオブジェクトはある程度拡張を考えていくため、データ構造が複雑になったりします。
不変なオブジェクトに対してデータを追加するというのはオブジェクトをまるごとコピーすることが必要となるため、大きな不変なオブジェクトに対しては処理も大きくなってしまいます。
可変なオブジェクトの場合は自動的に拡張できるため追加していくような処理に向いています。
このように2つの性質を持ったオブジェクトを処理内容によって使い分けしていきます。

可変なオブジェクトの作成

NSMutableXXX は可変なクラスとなっていて、これらの可変なクラスは不変なクラスのサブクラスとして実装されている。
不変なクラスのオブジェクトをまるごとコピーして可変なオブジェクトに変更することもできる
不変なクラスのインスタンス -> 可変なクラスのインスタンス
-(id) mutableCopy
というインスタンスメソッドを使用する事で可変なインスタンスを返す。

文字列クラス

> @""
というように文字列定数(文字列オブジェクトのオブジェクト定数)を書くと、
nilではなくて長さが0の文字列を表現できる。
文字列定数はプログラム開始から終了まで存在し続けてreleaseやガーベッジコレクションで解放されることはない。

NSString

(3)書式に従った文字列作成
NSStringではprintfのようなフォーマットで文字列を作成できる。
このうちの%@というのは対象のオブジェクトのdescriptionメソッドを呼び出した結果を埋め込んでいる。
descriptionはNSObjectで定義されているため、任意のオブジェクトを対象にできるが何を返すかはラクスの実装次第になる。

(10)パスの操作
文字列がファイル名のパス名を表現しているときに便利に使えるメソッドも用意されている。
NSPathUtilities.hに定義されていて、パスの分解して、ファイル名や拡張子を取り出したり絶対パス7日を判定したりできるメソッドがある。

NSData

バイト列からなるデータを扱う標準のクラス。
任意のバイト列をオブジェクトとして扱うラッパクラス。

NSArray

配列クラス
(7)ファイル入出力
ファイルの入出力はプロパティリストの形式で行われる。
writeToFileなどファイルに出力出来る。

配列オブジェクトとオーナーシップ

配列にはオブジェクトも入れることができるため、次のように書く複数のオーナーシップを持ってしまい解放することが困難になります。
NSArray *arr =[[NSArray alloc] initWithObjects:
	[[Card alloc] init], [[Player alloc] init], nil];
このコードを実行したオブエジェクトはCard,Playerのインスタンスのオーナーになり、配列arrについてのオーナーにもなります。
arrも要素のオーナーを持つことになるので、arrが解放されるときarrの中のオブジェクトそれぞれに対してreleaseが呼ばれます。そのため、arrを解放しても、arrが持っていたオーナーシップは放棄できますが、オブジェクトが持っている2つの要素のオーナーシップは残ったままになってしまう。

なので、autoreleaseして要素に指定するか、一旦変数に保持してから要素に指定する必要があります。
NSArray *arr =[[NSArray alloc] initWithObjects:
	[[[Card alloc] init] autorelease], [[[Player alloc] init] autorelease], nil];

// or

id card = [[Card alloc] init]; 
id player = [[Player alloc] init]; 
NSArray *arr =[[NSArray alloc] initWithObjects: card, plyaer, nil];
[card release];
[player release];
このようなオブジェクトを格納するためのクラスはコレクションといったりして、配列の他に集合オブジェクト、辞書オブジェクトがある。

高速列挙

配列や集合、辞書で格納する要素のオブジェクトを順番に取り出すためにfor...in構文による高速列挙というものがある。
for...in中では内容の変更はしてはいけなくて、辞書オブジェクトの高速列挙の取り出し順は内部実現に依存する。
列挙子 NSEnumerator
列挙子を使うことでもfor...inと同じように、列挙ループを行うことができる。
高速列挙と列挙子
高速列挙と呼ばれる所以は列挙子のように毎回メソッドを呼ばなくても列挙ができるため、for...inの方が高速であるからそういう。
列挙子はいらない子なのかというと、それは別の話で列挙子は列挙方法も指定できるため、次のように要素を逆順に取り出すなども行える。
enumerator = [myarray reverseObjectEnumerator];
for(obj in enumerator){
// fooo
}
また条件によって要素を読み飛ばしたり柔軟な判断もできる。
高速列挙はNSFasEnumerationプロトコルを実装しているクラスで使用できるようになっている。

集合クラス

NSSet
配列とは異なり、要素間での順番がなく、同じ要素が複数含まれないようなコレクションを集合オブジェクトと呼ぶ。cocoaではNSSetクラスで定義されている。
NSMutableSetのサブクラスとしてNSCountedSetという可変集合のクラスがあり、これは同じオブジェクトを複数回含むことができ、このクラスをカウント付き集合、バッグ(bag)と呼ぶ

辞書クラス

key valueなデータ構造を持ったNSDictionaryクラス。
NSDictionaryはクラスクラスタとして提供されているため、通常の方法だとサブクラスが作成できないことに注意しておく。

オブジェクト型ではないものを値に指定する場合はNSNumberやNSNull,NSValueなどのラッパクラスをできるだけ使う。

数値に対するラッパクラス

メソッドの引数にオブジェクト型を要求されることは多くの場面であるので、そういう時にラッパクラスが便利に使える。

NSNumber

NSNumberはそれぞれの方に対して生成メソッドなどがある
- initWith~
- initWithBool;
+ numberWith~
+ numberWithInt;
NSNumber型から値を参照するにはintegerValueインスタンスメソッドを使って取り出せる。

NSValueも大体同じ。

NSNull

配列などに要素としてnilを含めることはできない(末端を表してるから)
なので、NSNullを使い空のオブジェクトを表現する。
+ (NSNull *) null;
NSNullのインスタンスを返しますが、この返されるオブジェクトは常に同一のオブジェクトになる。
そのため obj == [NSNull null] でNSNullなのかを判定できる。

NSURL

URLやパスを扱うクラス。
ファイルのパスをNSURLで指定するメソッドも多い。

CHAPTER07 NSObject クラスとランタイムシステム
2011/09/11(日) 23:18 Objective-Cはてブ情報 はてブに登録 はてブ数

クラスとインスタンス

NSObjectはisaというクラス型の変数を一つだけ持っている。
isaは自分の属しているクラスオブエジェクトを参照しています。
このisaは直接変更や調べることはしないで。インスタンスメソッドのclassを使ったりする。
[Class class];
レシーバーの属するクラスを返すインスタンスメソッド。
同じようにクラスイメソッドもある。
レシーバー自身を返すメソッドもselfというのがある。(何もしないメソッドみたいな感じ)

メッセージ送信の仕組み

セレクタ(メソッド名)はコンパイル時に内部表現に変換されます。
この内部表現に対応するデータ型をSEL型と呼ぶ。
プログラム上からセレクタ内部表現を扱うために、@selectorというコンパイラ指示子を使ってお子なる。

SEL型を使ってメッセージの送信をすることもできて、performSelctorメソッドを使う。
SEL = method = (hanteishiki) ? @selector(activate:) : @selector(hide:);
id obj = (hanteishiki) ? a : b;
[target performSelctor:method withObject:obj];
というように、呼ぶ出されるメソッドを実行時に決定できる。

存在しないセレクタを指定してもエラーにならないから、-Wundeclared-selectorというオブションをつけてコンパイルするとチェックが出来る。

メッセージ探索

何度も同じメッセージを送るとき、
ランタイムシステムはあるクラスのあるセレクタに対応するメソッド持っていて、その定義場所はどこかをキャッシュしています。

オブジェクトのもつメソッドに対応する関数へのポインタはIMP型で表現される。これを使って直接間接を呼ぶことができる。

selfへの代入

initでselfに対して代入する形でやってるのは、self以外を返す可能性があるから。
// 引数なしのイニシャライザの実装
- (id)init {
    self = [super init];
    if (self != nil) {
    // 初期化
	}
    return self;
}

クラスオブジェクトとルートクラス

クラスオブジェクトのクラスに相当するメタクラスという概念がある。
任意のクラスオブジェクトがルートオブジェクトを継承したメタクラスのインスタンスであるとみなせて、
このことよりクラスオブジェクトはルートオブジェクトのインスタンスメソッドを実行できると言うことを意味している。
NSObjectのインスタンスメソッドとして定義されている、performSelctorなどを利用できるなど。

ターゲットアクションパラダイムという概念で、オブジェクト志向っぽい話。

新しいランタイムシステム

64bitのランタイムとiOSのランタイムをモダンランタイム
32bitのランタイムをレガシーランタイムと呼んでいる。

64ビットモデルと整数型

Cocoa環境ではNSInteger型を導入して、32bit環境ではint型、64bit環境ではlong型であるように定義している。
printfなどの型の違いで指定が変わるものは、キャストするなどそういうbit別のマクロ書いて対応してるみたい(apple的に)

CoreGraphocsではfloat型とdouble型がありましたが、CGFloatがたを導入して意識しなくてもいいようにしたみたい。

CHAPTER05 リファレンスカウンタを用いたメモリ管理方式
2011/09/04(日) 22:41 Objective-Cはてブ情報 はてブに登録 はてブ数

CHAPTER05 リファレンスカウンタを用いたメモリ管理方式

リファレンスカウンタ

Objective-Cでは参照カウンタを使ったメモリ管理をする。
インスタンスにretainを送ってインスタンスを保持したりする。
retainを送ることによってインスタンスを保持している状態を、インスタンスに対する「オーナーシップを持っている」という。
ただし、このオーナーという概念はObjective-C仕様には存在しない。

インスタンスの開放のためのメソッド定義

オーナーシップを放棄するためにはオブジェクトに対してrelaseを送りますが、、基本的にはdeallocメソッドをオーバーライドしてreleaseをします。
あるクラスのインスタンスを解放する = そのインスタンスが保持していたオブジェクトのオーナーシップを放棄する
ということになる。

自動開放の仕組み

CocoaのObjective-CにはNSAutoreleasePoolというクラスを使った自動開放の仕組みがある。
//プール作成
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

//たくさんのオブジェクトを登録

//プール破棄時に、登録したオブジェクトにreleaseが送信される
[pool release];
pool releaseで、登録したオブジェクトに対してひとつづつreleaseが実行される感じ。
使い道として、ループ処理の前後に挟んでやるとか(ただ、breakなどするとあぼん)
もう一つはGUIを使ったアプリで、マウスキーボードを監視して対応したメソッドを呼ぶ感じの実行ループの時に使うなど。

オーナーシップポリシー

オーナーシップポリシーとは「インスタンスオブジェクトのオーナーが、そのインスタンスの開放に関して正規人を持つ」ということににする取り決め。

オブジェクトが別のオブジェクトのオーナーになるとはどういう場面?
allocによるインスタンス生成
クラスに対してallocする、newなどでインスタンスを生成した場合、メッセージを送ったオブジェクトが新しく生成されたインスタンスのオーナーになります。
copyによるインスタンスのコピー
copy系のメソッドで、インスタンの複製を生成した場合、メッセージを送ったオブジェクトが、新しく複製されたインスタンスのオーナーとなる
retainによる保持
あるインスタンスにretainメッセージを送って保持した場合。
メッセージを送ったオブジェクトが、レシーバであるインスタンスのオーナーとなる。
つまり、一つのインスタンスに対して、複数のオブジェクトがオーナーとなることができる。
= インスタンスの共有
インスタンスのオーナーがreleaseやautoreleaseをするのは当然だが、逆にそれ以外のオブジェクトがreleaseすることは原則禁止。

メッセージの送受信とオーナーシップ

メッセージの引数にオブジェクトを送る、返り値がオブジェクトの場合について。
基本的にはオーナーシップの移動は起きないものとする。
渡した先でretainによる保持を行う事は自由に行える。
逆にインスタンスを渡す側がそのインスタンスを使わないからautoreleaseしてオーナーシップを放棄してから渡すという事がある。
この2つが同時に起こるとオーナーシップが移譲されたように見えてしまうのが混乱の元。
- (id)temValue{
	id tmp = [[ComplexData alloc] init] initWithData:myValue];
	return tmp;
}
このようなメソッドの場合、メソッドの実行が終了した時点で、生成されたインスタンスにはオーナーがあに。メソッドの呼び出し側がretainしたとき呼び出し側がオーナーとなるが、何もしなければ自然消滅する。

一時的なインスタンスを生成するクラスメソッドをObjective-Cではコンビニエンスコンストラクタという。
allocとinit、autoreleaseを呼び出してインスタンスを返すようなクラスメソッドの事。

開放しないオブジェクト

NSString文字列のようなオブジェクト定数の事。
これらのオブジェクトにretainCOuntのメッセージを送るとUINT_MAXという値が帰ってくる。
開放したくないオブジェクトを定義するには、クラス定義でretain,release、retainCountを書き換える必要があり、これらのメソッドのsuperも呼び出さないようにする。
そして、retainCountが常にUINT_MAXを返すようにする。
これを使うのはシングルトンぐらいで、シングルトンはsharedから始まるクラスメソッドを持っていて共有される唯一のインスタンスを返すように実装されるためである。

CHAPTER03 継承とクラス CHAPTER04 オブジェクトの型と動的結合
2011/08/24(水) 14:44 Objective-Cはてブ情報 はてブに登録 はてブ数

クラスの継承とself

selfはメッセージを処理しているインスタンス自身を示しているため、継承したメソッドを呼んでるつもりでもインスタンス自体にあるメソッドが呼ばれる。
つまりselfは動的に変わる。

superの場合は継承したクラスのメソッドを示すことがコンパイル時の依存関係から決定するため、静的に呼び出すメソッドは決まる。

局所的メソッド

インターフェース部で宣言してなくても、メソッドを実装すればそのクラス内の局所的メソッドとして利用ができる。
だが、継承などで誤って上書きしてしまうことなどがあるため、Appleのガイドラインでは居所的メソッドに特定の接頭辞を付けることが推奨されている。

動的束縛とは

Objective-Cでは送られてきたメッセージに対応してどのメソッドが実行されるかは実行時に決定します。その方式を動的束縛、動的結合と呼ぶ

ポリモーフィズム

同じメッセージを送っても、レシーバーのオブジェクトに応じて適当なメソッドを呼ぶ性質をポリモーフィズムと呼ぶ。
[target move:direction];
この場合、変数targetがポリモーフィズムくを実現しているオブジェクトならば、オブジェクトtargetが受け取ったメッセージにより、どういう処理をするかを決めればいい。

空のポインタnil

ポインタが実体を何も示していないことを表すためにnilという値が用意されている。
nilはid型の空のポインタで、値は0になる。

型の静的チェック

Objective-Cはコンパイル時に型チェックを行います。
id型は(void *)のように何でも適応できてしまう型なので、型チェックができなくて困るので、
クラス名を型名にちゃんと使ったほうがよい。

プログラミングにおける型宣言

- (id)cellAtRow:(int)row column:(int)col;
おのようなセレクタと型情報を合わせたものをシグネチャと呼ぶことがあります。
Objective-Cにおいては基本的に、同じセレクタを持つメッセージは引数や返り値の型(シグネチャ0を同じにすべきである。
オーバーローディング
CやJavaなどで引数の型などが違うプロトタイプを複数宣言して、渡す引数によって処理を選択できることを多重定義、オーバーローディングという。
Objective-Cは動的束縛で実行時に引数の型が決定されるため、このような多重定義は行えない。
代わりに、以下のようにメッセージセレクタ(ラベル)の違いによりオーバーロードが可能であるとも言える。
- (int) test1;
- (int) test1: (int) a1;
- (int) test1: (int) a1 arg2: (int) a2;

@class クラスの前方前言

ヘッダー内で、特定のクラスの型を使いたい場合、そのクラスのヘッダーファイルを読み込むと再帰的に読み込みが起きたりするため、代わりに@classディレクティブでクラス名の使用を宣言します。
@class Volume;
という感じでVolumeというクラスを使うことを宣言できます。これをクラス名の前方宣言という。
(実装部では使用するクラスのヘッダーファイルが必要になるかもしれないが)

インスタンス変数の隠蔽

Objective-Cでは基本的にオブジェクトの外からインスタンス変数にアクセスすることを許可しません。
アクセサ
インスタンス変数には直接アクセスしないで、アクセサというgetter/setterを通してアクセスするのが普通です。

クラスオブジェクト

クラスオブジェクトはオブジェクトして機能するために、それ独自の変数やメソッドをもっています。
インスタンス変数 <-> クラス変数
インスタンスメソッド <-> クラスメソッド、ファクトリーメソッド
クラスメソッドはファクトリーメソッドとも言われることがあり、allocなどが典型的な例です。
クラス変数
Objective-Cはクラス変数が構造上ありませんが、static指定子を使い変数を宣言したものをクラス変数の代用とすることもできる。
Objective-Cのクラス変数は基本的に外部に公開してつかうものではない。

イニシャライザを返す型

Objective-Cではイニシャライザを返す型は一般的にidがたにしておくべき。

CHAPTER01-02
2011/08/23(火) 18:45 Objective-Cはてブ情報 はてブに登録 はてブ数

オブジェクトの属性

Objective-Cでは他のオブジェクトを参照するための変数のことをことをアウトレットと呼ぶ。
Interface Builderではこの用語が使用されている。

メッセージ式

[obj msg];
いわゆる関数を呼ぶためにobjはメッセージ(msg)を処理した結果の値を返す。
これをメッセージ式と呼ぶ(関数呼び出しのこと)

メッセージセレクタ

関数を関数名で呼ぶように、メッセージ(msgの部分)をメッセージセレクタ、セレクタ、メソッド名と呼ぶ。

インスタンスの生成と初期化

alloc,initで行うことが大抵。
[[クラス名 alloc] init];

クラスの実装部

メソッドの定義中で、そのメソッドの使ってるインスタンスオブジェクト自体を表したい時はselfを使う。selfはインスタンスオブジェクトを示す。

静的な変数定義

static指定子を使うことで、静的な変数を定義できる。
また、static変数ははインスタンスオブジェクト分できるのではなく、インスタンスしたオブジェクトで共有される。