完全なC互換。CocoaはObjective-CのAPI。Cocoaについて学べば必然的にObjective-Cについて学べます。主な開発環境はXcode(または旧Project Builder)。プログラミング言語
一般的な Object 指向の思想を理解してゐる前提の元に文法事項を解説。全てを粒さに讀む必要はない。Cocoa の方をやりながら文法事項を知りたいなと感じれば、外國語の學習同樣に、必要な時に必要な所を參照した方がよい。
Objective-C では新たに次の樣な型が定義されてゐる(objc-class.h)。
言語構造上の變數は
など馴染みの物がある。これらは一例に過ぎないし全てを遣ふわけではないから、追々説明する事になるだらう。
定義は.hファイル、實裝は.mファイルに書く。Xcode で新たに書類をプロジェクト追加する際に、Objective-C Class テンプレートを選ぶと、.hファイルと.mファイルが自然に追加される。
// MyObject.h
@interface MyObject : NSObject{
}
@end
// MyObject.m
@implementation MyObject
@end
Objective-C では C と區別(或いは將來の互換性確保)の爲に、擴張した文法は@を附け記述する(ディレクティブ參照)。今この記述では、NSObject を繼承した MyObject クラスの定義をした事になる。
註:新たにクラスを定義する場合は、一般に NSObject を繼承したクラスを定義する。その理由は NSObject が Cocoa における一般的な手續きを全て網羅してゐるからである。またその他のクラスに於ては、特段の理由や意味がない限り、サブクラスを造らない方が良い(譬へば NSString や NSArray のサブクラスを作製しても思ふ樣にはいかないだらう)。逆に能くサブクラスを作るのは、NSObject の他に、稀だが NSApplication の場合や、或いはサブクラスを作る爲のクラス NSManagedObject 等である。
目的別に使ひわけることになる。
クラスは大文字で始めねばならない。Objective-C は 大文字と小文字を峻別する。今幾つかクラス名を擧げてきたが、自身のクラスを作る際に NS を接頭辭としてはならない。NS は NeXTSTEP の略であり、今では Apple による API を區別する爲のクラス名接頭辭として「豫約」されてゐる規約である。注意して欲しい。他にも IO(Input-Output)や OS(Operating System) や CG(Core Graphics)等 API 系により、ある程度の先客があるので、紛らはしい名前は避けた方がよい。
今先程のクラスに、インスタンス變數 obj、クラスメソッド myClassMethod、メソッド myMethod を追加したとすると、
// MyObject.h
@interface MyObject : NSObject{
id obj;
}
+(void)myClassMethod;
-(id)myMethod;
@end
// MyObject.m
@implementation MyObject
+(void)myClassMethod
{
/// your code
}
-(id)myMethod
{
return obj;
}
@end
ヘッダにおける括弧の遣ひ方に注目して欲しい。括弧はインスタンスが保持する變數を記述する箇所で、メソッドを記述する箇所ではない。クラスメソッドは+、インスタンスメソッドは-で書き始める規則がある。以後メソッド名と共にクラスメソッドかインスタンスメソッドかを示す際には ± を以て明示する事にする。
さてメソッドは、@ の圍み、@interface ~ @end と @implementation ~ @end に於て記述する。文字通り定義と實裝を表す。なほ Objective-C は完全な Object 指向を目指す物ではなく實用を任とする言語であり、Ruby の Kernel Object 樣な物は無く、詰り通常の函數は C と同じ方法で定義し利用できる。だから圍みの外で函數を定義するとよい(註:C のコードとは共存できる)。
今、更にこの MyObject のインスタンスを保持した變數 receiver が存在したとすれば、二つのメソッドを呼出すには、
[MyObject myClassMethod];
[receiver myMethod];
と書く(結果を取得するなど變數の扱ひは C と全く同じなので略)。Objective-C に於てインスタンスをレシーバと呼ぶが、その意味は、Objective-C に於けるメソッドの呼出され方・動作に由來する。一般に「レシーバにメッセージを送る」と謂へば、インスタンスメソッドを起動する事を意味する。
註:id型はObjective-Cに於て新たに定義された型の一つで、任意のレシーバを表す型である。この樣な汎用的な型については附録參照。
引數を渡すには幾つか規則が存るが、先づ單純な一つ渡す方法を示す。今 id 型の變數 value を -myMethod に渡すとして、
[receiver myMethod:value];
と書く。メソッド名の後に :(コロン)を打つて引數を書くと、レシーバにメッセージが送信される。上の定義と實裝を書き直せば、
// MyObject.h
@interface MyObject : NSObject{
id obj;
}
+(void)myClassMethod;
−(id)myMethod:(id)val;
@end
// MyObject.m
@implementation MyObject
+(void)myClassMethod
{
/// your code
}
−(id)myMethod:(id)val;
{
return obj;
}
@end
更に複數の引數を渡したいのならば、可變長かラベルを利用する事になる。
註:Xcode で Cocoa アプリケーションを開發するならば、メソッドを呼び出す時は、ヘッダが解析された後に入力支援システムによつて補助が入り、どこにコロンを打ちどこにどんな變數がと云ふ事を惱む必要がなくなる。だから今一番憶えておきたいのは、寧ろメソッドの記述方法である。
C における可變長と同じく、可變長引數を id 型にすれば
+(void)myClassMethod:(id)objects, ...;
と書ける。
Objective-C で尤も一般的な複數引數の記述・利用法がラベルである。Objective-C では、その他の言語での引數がただの變數の羅列になるのとは對蹠的に、引數に名前を指定する。この名前をラベルと謂ふ。座標を渡すメソッドを考へたならば、
[receiver myMethod:val withX:x withY:y];
−(id)myMethod:(id)val withX:(int)x withY:(int)y;
と書く。ラベルの導入は code を著しく簡明にする。C の函數等で myMethod(val,num1,num2); と書くと引數の意味が取りづらいが、Objective-C では上にある樣に見目に分り易くなつてゐる。詰り打鍵數は増えるかもしれないが、それでもなほ利點が大きいと判斷された爲に、ラベルは導入されたのである。
またこのラベルは同じメソッドで幾通りも用意できる。今上に示した樣なメソッドはドキュメント等では myMethod:withX:withY: と書く事で略記されてゐるが、myMethod:withX:withY:withZ: なるメソッドを作りたいと思つた時、myMethod:withX:withY: と myMethod:withX:withY:withZ: は共存できる。
註:一つだけの引數の場合はラベルがない樣にみえるが、次の樣な解釋ができる。卽ち上のメッセージは「myMethod:、withX:、withY: と云ふ三つのラベルを有してをり、myMethod: の如きメソッド名の樣にみえる表記はラベルを表してゐるに過ぎぬ」と謂ふ物である。つまりレシーバに引數を送信する爲には必ずラベルをつけたメッセージを送るとみれるわけ。なほラベル自體は文法上必須ではなく、メソッド名だけでも良いが、上に擧げた「見目に分り易い」ことが重要なのである。
Objective-C は柔軟すぎる言語である。中にはかなり邪惡或いは病的な手段も存在するが、それらの使用は全てプログラマ委(まか)せとなつてゐる。これは Objective-C が弱い型附けである事と同じ理由であらう。今は親クラス(superclass)のメソッドを上書き(override)する方法を示す。
<準備中>
註:上書きする場合はいちいちヘッダに書く必要は無いが、若し書きたいと思ふのなら、書いても問題はない。
Cocoa API を見て行くと暗默上の諒解が幾つもある。この事はもう少し後に扱ふべき内容であるから、API をみて何かあると感じた時、規約がある事を思ひ出して欲しい。
今 NSString のメソッドを例にすると、
等が即座に指摘できる。これらは順にドキュメントを讀んだりしながら、各が會得して欲しい事項である。
Objective-C におけるインスタンスは、C のポインタである。だから變數の型にはポインタを表す * が必須である。
NSObject *obj = [[NSObject alloc] init];
このインスタンスたるポインタに、Objective-C の Runtime が、メッセージを送受信してオブジェクト指向たらしめてゐる。なんとなれば、id 型は void * 型と等價であると謂ふ事だが、一つだけ違ふ點は、id 型が Objective-C のレシーバであると保證してくれる事である。だから任意のクラスのレシーバを利用したい場合は id 型を用ゐるとよい。
レシーバの初期化は上にあげた +alloc, -init が尤も基本的な物であるが、ファクトリメソッドが用意されることもある。遣ひ分けは後々メモリ管理で論じるが、今はメモリリークは一切氣にせずに、初期化法を考へてみる。
alloc と init は NSObject(より正確には NSObject Protocol)で定義されてをり、Objective-C の根幹を成すメソッドの一つである。alloc はレシーバにメモリを割り當てるが、この alloc は上書きしてはならない。init はこれを初期化するが、自身の初期化をコードを用ゐたいならば、上書きしてもよい。
註:オブジェクトの所有權についてはメモリ管理をみて欲しい。より詳しい初期化についての事はそこで述べることになる。
Objective-C では、nil に存在しないメッセージを送信しても、エラーが發生しない。これは通常のレシーバでは致命的なエラーとなる事と異なる結果を導くので注意して欲しい。
[nil myMethod];// エラーにならない
[receiver myMethod2]; // myMethod2が未定義ならばエラー
これは譬へば delegate で nil を設定しても呼出しに惱む必要がない等、ただメッセージを送信するだけの用途のコードのエラー處理を短縮する事になるだらう。
Objective-C のメモリ管理は「參照カウント」と「ガベージコレクション」が用意される。Mac OS X はメモリリークしたメモリであれプロセス終了時に回収してくれるが、實行時にメモリを大量に利用する場合メモリ確保が困難になるかもしれない。だからなるべくメモリリークを防ぐコードを書くべきである。ここでは參照カウントにまつはるメソッド、つまり NSObject に實裝されてゐる NSObject Protocol の +alloc、-init、-retain、-release、-autorelease、そして NSAutoreleasePool class を解説する。なほガベージコレクションを利用する場合は Mac OS 10.5 以降に導入され以前のバージョンと互換性がないので注意する。
一般に上から順に實行する。Objective-C Runtime は、メソッドを實行し終はると、alloc で 生成したオブジェクトにメモリ解放するメッセージ [receiver release]; を自動的に送る。だから任意の瞬間にオブジェクトを解放したいのならば、retain によりカウンタを増し release によりカウンタを減らせばよい。release は參照カウントが 0 になればオブジェクトを解放してくれる。
上で示した仕組みでは時に問題が起る。メソッドの戻り値としてメソッドが生成したオブジェクトを返す場合である。
−(id)myMethod
{
NSObject *val = [[NSObject alloc] init];
return val;
}
今この樣なメソッドの戻り値を利用する場合を考へる。しかし Runtime によつて、このままでは val に release が送信され、取得した時點では既に解放されてゐる。假に retain してみればどうなるであらうか・・・・。
簡易コンストラクタは autorelease されたオブジェクトを返す。
唯一でなければならず、しかも retain されてゐるオブジェクトを返す。取得した側で責任を持ち release する必要がある。
これらで取得する場合は、簡易コンストラクタと異なり、retain されてゐるので、オブジェクトが不用になつたならば、プログラマは release せねばならない。しかしそれ以外の手段(メソッド)で取得できるオブジェクトは autorelease されてゐる。この點に注意されたい。
Cocoa における Root class の一つ。實は NSObject のメソッドは NSObject Protocol と NSObject Class のメソッドとに分類できる。
註:Cocoa における Root class は NSObject Protocol を適用する事になる。NSObject Protocol には基本的なメソッドが全て列擧されてゐるから。NSProxy 等。
Ruby における module みたいな奴。任意のクラスに幾らでも適用できる。Ruby module が實裝ならば、Obj-C Protocol は宣言に過ぎない。手法が明示的なる物と暗默なる物の二種類ある。
カテゴリは定義濟のクラスを擴張できる、Objective-C でも一・二を爭ふ邪惡で、そして便利な手段である。譬へば今 NSString に base64 encoding のメソッドをつけ加へてみたいと思ふならば、カテゴリを用ゐることで實現できる。
配列なんかで用ゐる。NSMakeRange で生成できる。
NSView 及びそのサブクラスでよく使ふことになる。NSMakeSize。
Objective-C におけるコンパイラ及びプリプロセッサへの命令について。C 標準は勿論のこと、幾らかの擴張がある。それが以下である。
#import は #include に同じだが、一度しか讀み込まない點が異なる。// は行末迄コメントと解する。
互換性確保の爲に @ で書き始めると謂ふのは、@interface の紹介をした際に書いた。今クラス(そしてそのカテゴリ、プロトコル)を宣言する手段をみれば、
があつて、必ず@end で宣言を閉ぢる。そのインスタンス變數の可視性は次の宣言で示す。
初期設定は@protectedである。例外処理は、
@finally が強制實行部位で、あとはお馴染みか。更に特定の目的が爲、次が用意される。
一往説明が必要なのは @"string" であらう(其れ以外は取り急ぎ必要がないから述べない)。@"string" は quoted な部位を NSString class のレシーバとして處理する構造である。@"abc" と書けば、abc なる文字を保持した NSString class のインスタンスが const として生成される。しかも(同じ stack であればだと記憶するが)@"string" を同メソッド内で何度呼びだしても、同じインスタンスを返してくれる。
言語仕樣に明るいわけではないが、譬へば NSFastEnumeration Protocol の登場以降(Mac OS X 10.5以降)では、コンパイラは C 標準にない for 文をサポートしれくれる。これもディレクティブである。たまに C 標準ではない物があるとすれば、現在のプログラミングでは一般的な表記を、實用に利する爲に取り入れた表記群であらう。
Mac OS X のメモリ確保方法について。malloc_zone_malloc とかの話。malloc.h みて下さい。
Xcode は Apple による工夫によつて擧動に「癖」がある。
SDK を意識することは結構重要で、API の統廢合は結構よくある。最新の Document をみるか、API のヘッダを讀めば書いてある。LEGASY とある場合は、なるべく遣はない方がよく、新機能新API らしい物は當然互換性の障碍となるから注意である。
恐らく debug になつてゐるので、「出荷」するときは release にするやうに。ビルド構成は、ビルド時に指定するコンパイラオプション等を保存した物で、任意に切替ることができる。
作る實行ファイルのこと。ビルド前は存在しないから赤い文字で表記される。
<デバッガの遣ひ方とか mark の仕方を書きたいのだけれど?>
Cocoa Application では precompile と呼ばれる工程がある。pch ファイルは、C++ でもお馴染みかもしれないが、Precompiled Header の事である。precompile とは文字通り compile の前段階のことで、簡單に謂ふと、キャッシュを用意する事で Cocoa Application のビルド時間が短縮できる。Xcode でこれを編輯することは先づないので、飾り程度に認識しておくとよい。
ただこのキャッシュは 30MB 程度あつて輕くない。10.4 以前なら /Library/Caches/Xcode に、10.5 以降ならば /private/var/folders 下にある -Caches-/com.apple.Xcode.501 に纏まつてある。たくさん Cocoa Application を作つてゐるとこのサイズは途轍もない物になるので、不安になればたまに削除すると宜しい。尚 /private/var/folders 以下は、人によりフォルダが異なるし、501 は UID なので、若し UID が 502 ならば com.apple.Xcode.502 になる場合もあるかもしれない。
@"string" でわかるように、const は使用可能。static は singleton で用ゐる。
インスタンス變數は C での構造體のメンバの樣に宣言運用できる。例としてあげれば、@interface 中に int nums[10]; とできる。
メソッドを呼出す行爲は、レシーバの情報から函數ポインタを取出し、それを呼出してゐるに過ぎない。今 <objc/objc-class.h> を import した上で、
id obj = [self getObject]; Method method; Class class = [self class]; SEL name = @selector(myMethod:); method = class_getInstanceMethod(class, name); #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5// OBJC2 UNAVAILABLE method->method_imp(self, name, obj); #else method_getImplementation(method)(self, name, obj); #endif
とすれば、これは [self myMethod:obj]; と同等である。ここで #if を用ゐるのは、Method のメンバにアクセスできるのは、32 bit 環境且つ Mac OS X 10.4 以前のみだから(正確には Objective-C 2.0 で削除された仕樣であるから)。尚、メソッドを上書きしてゐなければ、self とは別のインスタンス等でも函數ポインタは同一である。若し同一かどうか不安であれば、NSLog(@"%p", method->method_imp); として確かめてみればよい。
註:譬へば method を NSValue のインスタンスに格納して後々利用しようと思ふならば、name が欲しい事もある。その時は、method->method_name 或いは method_getName(method) とすればよい。
Outlet はインスタンス、Action はインスタンスのメソッド。
註:IBOutlet 及び IBAction は C のマクロである。IBOutlet はコンパイル時に無視され、IBAction は void * を表す。
Application Kit (AppKit) には、さまざまな御約束がある。ある程度馴れてくると、ヘッダをみて、通知や委讓がないか確かめたり、クラスの使ひ方がわかるようになる。
API はよく遣ふ物を特に説明する。ただし Core Data については割愛する。
恐らく尤も頻繁に作られるクラス。
NSDictionary や NSArray に int や nil や 構造體等を納めたい場合にはこれらを用ゐる。NSValue でラップできる物については @encode() 參照。
dataSource と delegate をうまく遣ひこなすこと。
NSTableView 同樣。
カスタムビューに何か御用ですか?
NSWindow *w = [myView window]; BOOL ended = [w makeFirstResponder:w];
Document-based Application で大活躍。[NSDocumentController sharedDocumentController];
[NSApplication sharedApplication];
要約として次に用意されてゐる。構文もまた參照せよ。
Cocoa とは、Foudation Frameworks、CoreData Frameworks、AppKit Frameworks により構成される Objective-C の API 群である。
Foudation は、そのまま「基層」の意である。化粧をする貴方には下地(ファンデ)でおなじみ。Cocoa で尤も酷使される可哀想なやつ。一方で、これの扱ひになれれば Cocoa API はグつとわかりやすいものになる。
抽象的で申し訣ないが、要するには Cocoa の頻出データ型を定め頻出する機能を纏めたやつである。MVC でいへば Model の提供が主で Controller の技術的補助(オブザーバなど)、View に渡すデータなどの役割を擔ふ健氣なやつ。
AppKit は、ApplicationKit の略である。Kit の接尾辭は Apple では擴張的であれど基本的な API 群につけるらしく、たとへば Safari の KHTML エンジンは WebKit Frameworks で實裝される。Cocoa にラップされた QuickTime API は QTKit である。
感覺を摑むためにも、まづは手元にある Interface Builder を起動させてみて欲しい。起動せば何か作るかと聞いてくるから、Cocoa > Window を選ぶ。Untitled とある畫面にはタブがあり、Instances といふタブが選擇されてゐるはづである。 Cocoa > Window の nib テンプレートには File's Owner、First Responder、Window とある訣だが、Window のアイコンをダブルクリックして欲しい。 君の目の前には眞つ白な「ウインドウ」が現れるだらう。多分表示されてゐると思ふけれど、パレットが無ければメニューから「Tools > Palettes > Show Palettes ⌘/」を選びたまへ。次にこれもおそらく表示されてると思ふけど、パレットにカラフルなイラストで彩られた上段のタブなければ、右上のボタンで表示するやうに。
さあ簡單に説明しよう。これが Cocoa AppKit のインスタンス君たちである。ツベコベいはず、Controls、Text、Data、Containers などの名前付きのタブから部品をマウスで選び、先程私がダブルクリックしろと言ひ散らして君が放つたらかしにしてる「ウインドウ」にドラッグドロップせよ。 あないみじ。何か表示されるね? ああ、されないなら君の Mac OS X Developer Tools は缺陷品だから、抗議の電話をしたまへ。
これが "インスタンス" だ。君がこれから作るアプリケーションはこの Interface Builder で概觀をデザインすることになる。
なほこの インスタンス 豫定部品君たちは Cocoa の高度な抽象化により、君がコードで宣言しなくても Mac OS X によつて勝手に初期化されて表示されることになる。君はではこれの値を變へるにはどうすれば、と思ふだらうから簡單にいふと、委讓關係を設定するか Binding を利用するかになる。恐ろしいことにこれも全て Interface Builder で且つグラフィカルに設定できてしまふ。 先程ウインドウに君はインスタンスを載せた。ボタンやらコンテナやらである。control キーを押し乍らそのインスタンス部品をクリックしてマウスを動かしてみれ呉れ。何か線がニョロニョロ出てくるだらう? これが委讓關係を設定する一つの手段である。細かい事は割愛しようと思ふが、便利でわかりやすいけどわかりにくい構造とならしめてゐる Interface Builder の一端が垣間みれたのではないかな。
すでに他のオブジェクト指向を味はつた貴方に説明するなら、これは Key-Value Coding Protocol(KVC)、Key-Value Observing Protocol(KVO) が活躍することになる。KVC は setter、getter、そして KVO は Observer パターンを實裝するもので、NSObject をルートとするクラスには自動的に備はる機能になつてゐる。protocol は Ruby 的な感じだと規約に當たる物で、かうしませうといふ感じのメソッドの一群。protocol は Objective-C の文法的要素でもある。protocol を實裝したクラスは、protocol の規約に從ひメソッドを定義せねばならない。ただしこれはインスタンスの構造に變更を加へるときのみ必要なだけで、單純に NSObject を繼承したクラスでは KVC の protocol に適合してゐることになる。
先程載せたインスタンスらは nib ファイルに格納し保存される。インスタンスは plist 形式でシリアライズされてをり、Mac OS X のアプリケーションは起動時にこれを參照し復元して GUI 環境を提供してくれる。plist は Foudation の一部のクラスをシリアライズする物で記法は三種類ほど存在する。よく使ふので別項で解説する。nib ファイルはアプリケーションバンドルに必ずあるので、「パッケージの内容を表示」して探してみて欲しい。
MVC でいへば、まさしく View を擔當することは先程の Interface Builder でよくわかつたかと思ふ。Controller もちょっち擔當。
Core Data は、WebObjects の EOF(Enterprise Objects Framework)の流用である。さつぱりわからん? まあ聞いてくれ。Core ImageだとかCore Audio、Core Video、などのイメージがあるので、私はハードウェア的な實裝なのかとつい勘違ひしたが、これは頗るソフトウェア的である。Core の接頭辭は Carbon API のやうに C で實裝された API をラップする存在に附けられるやうである。先述の Foudation は Carbon API の Core Foundation をラップする。これらは、高速化を圖るための思はれる。
WebObjects はマイナーの嫌ひがあるので説明せば、Mac OS X に無料でバンドルされる Java Servlet の類ひである(なほ元々は純粹なobjcだつたがversion.5よりJavaになつた)。EOF は WebObjects の賣りのひとつで、 サーバ毎に Adaptor を巧みに遣ひわけ猶且つ SQL をデヴエロツパが書く事無くして DataBase を操作する代物であつた。
Core Data は、主に書類を扱ふ際に威力を發揮する。EOF との違ひは、EOF は Java Servlet といふ用途に沿ふ實裝だが、Core Data はデスクトップアプリケーションの爲の API であるといふことである。そこらへんのことは Apple の Core Data の解説に詳しい。
長くなつたけど、序論である。AppKit に項目を割いたのは Cocoa GUI に於いてとても重要であるからである。
また、下記リファレンスの URI に於いて CoreData を除き「ObjC_classic」とあるのは何故かと思はれるかも知れないので付け足して置くと、Foundation と AppKit は OPENSTEP 時代からの遺産であつて、Core Data は Mac OS X Tiger(v.10.4) より導入されたに過ぎない。 ゆゑにクラシックなのである。
Foundation Framework Reference
AppKit Framework Reference
CoreData Framework Reference
Cocoa バインディング入門(邦譯版)
Core Data プログラミングガイド(邦譯版)
「キー値コーディング」及び「キー値監視」について(邦譯版)
Core Data のレビュー記事。KVC、KVO、Cocoa Bindingにも觸れる「TigerのCocoaにみるMVCの完成 - スマートなデータモデルを実現するCore Data」(マイコミジャーナル・コラム)
Foudation Frameworks は Carbon の完全なラッパーとなつて居る。幾つか憶えるべき最低限のものを擧げてみれば、それは NSString、NSArray、NSDictionary などのクラスである。まづ、基本的なクラスを紹介する。
NSObject はルートクラスであり、次のプロトコルに "接續" する(Adopted Protocol)。
これらのプロトコルで實裝されるのはインスタンスメソッドのみとなる。Cocoa では次のステップを踏みインスタンスを生成する。
NSObject *obj = [NSObject alloc]; [obj init]; [obj autorelease];
alloc はデザインパターンの Factory にあたり、Objective-C ではこのクラスメソッドがメモリ確保を行ふ。絶對に子クラスで上書きしてはならない。なほ alloc は NSObject に實裝されてゐる。これを「割り當て」と呼ぶ。他の言語のやうに new Class といふ記法はないが、new メソッドが存在する(後述)
後述の NSArray や NSString といつたクラスのクラスメソッドには次の物がある。
+ array + arrayWithArray + string + stringWithCString:encoding: + allocWithZone + newarray*** とあるのは NSArray の Factory であり、string*** とあるのは NSString の Factory にあたる。Cocoa の Factory は戻り値として初期化する前のインスタンスを返す。なほ Objective-C では + を伴ふメソッド定義がクラスメソッドを示す。
割り當てられた領域は NSZone クラスのインスタンスとして(zone メソッドにより)取得することができ、allocWithZone で生成すれば同じ領域を使用できる。また、參照カウント及びインスタンス變數の初期化を行ふ。ここに於いて isa インスタンス變數の決定といふ重大な過程を經過する。
init は初期化メソッドであり、インスタンスメソッドである。子クラスで繼承できるが、親クラスのインスタンスメソッドを實行させること。NSObject に實裝。
- (id)initWithArray:(NSArray *)array - (id)initWithTimeInterval:(NSTimeInterval)secsToBeAdded sinceDate:(NSDate *)anotherDate - (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag - (id)initWithFrame:(NSRect)frameRectこれも同樣に init*** といふ命名規則を持つ。これは NSSet、NSDate、以降はAppKit だが NSWindow、NSControl(及びNSView) などのメソッドである。
似たやうなメソッドとしてinitializeがあるが、こちらは「クラス」の初期化を擔ふ。一度しか呼ばれない(後述)。なほ初期化した自身を返すのだが、 id 型を返すとあるのはこれを不特定の何か程度に認識して於いてほしい。C の爲に存在し、Objective-C では id 型がオブジェクトを指す。
autorelease は自動で release する、すなはちメモリ解放の爲の手續きである。最近の言語では garbage collection は最早定番とも言へるがこれも似た手段である。解放プールに入れると表現されるが、それはアプリケーション起動時に NSApplication が NSAutoreleasePool クラスのインスタンスを作り、これに叩き込んで監視するからである。
- autorelease - release - retain - retainCountNSObject Protocol によつてこれらのインスタンスメソッドが定義される。autorelease は明示的に release をするのと變はらぬ效果を與へる。retain は參照カウンタを増大させ release は參照カウンタを減少させるものだが、NSArray といつたコレクションクラスに插入すると自動的に retain が呼ばれ參照カウンタが増える仕組みになつて居る。不要になれば release か autorelease を呼ばねばならない。
正確な意味での garbage collection は Objective-C 2.0 への擴張で組み込まれ Leopard より實裝された。保守的(conservative)な GC である。
他にインスタンス生成に於いて俯瞰せしめた際に見渡せることを書連ねる。Cocoa では isa インスタンス變數を組み込むことでクラスを識別する。かういつたクラスに關する處理で特殊なものがあるから紹介する。
### NSObject: Adopted Protocol ## NSObject Protocol # Identifying and Comparing Objects - isEqual - hash - self # Describing Objects - description # Sending Messages - performSelector # Determining Allocation Zones - zone # Identifying Proxies - isProxy ### NSObject Class: Tasks # Initializing a Class + initialize + load # Creating, Copying, and Deallocating Objects + new - dealloc - finalize ### NSString Class: Tasks - hash - isEqualToStringあるプロセスに於いて NSMutableString クラス(NSMutableString > NSString > NSObject)が始めて呼びだされたとして、その時に NSMutableString のクラスメソッドたる initialize が自動的に呼び出される。親クラスたる NSString クラスの initialize が呼び出されてゐない場合も同樣である。また、load クラスメソッドもクラスがプログラムに讀み込まれたことを告げるために initialize を呼ぶ前に呼び出される。すなはち次の順となる。
[NSObject load]; [NSObject initialize]; [NSString load]; [NSString initialize]; [NSMutableString load]; [NSMutableString initialize];new クラスメソッドは次の式と等價である
[NSObject new]; # Pattern1 NSObject *obj = [[NSObject alloc] init]; # Pattern2 NSObject *obj = [[NSObject alloc] init];ただし、new に渡された引數は init にも渡されることになり、alloc と異なり子クラスで上書きしても構はない。
dealloc はメモリ解放を行ひ、release により呼び出される。明示的に dealloc を呼ぶ事は無い。獨自のメモリ解放機構を備へるなど子クラスで再定義できる。
finalize は dealloc に代はり呼び出される。GC が有效なとき、autorelease を呼んだときなど(よくわからんから調査中)。
description 則ち「説明」とあるけど、これは NSString にインスタンスを變換しこれを返す。所謂「toString」「to_s」 などのメソッドと考へて欲しい。isEqual は何が「イコールか?」と云ふとインスタンスの hash メソッドを用ゐて比較した眞僞値を返す。たとへば、NSString クラスでは hash メソッドが再定義され、同時に isEqualToString が追加された。isEqualToArray、isEqualToDate、isEqualToSet など似たメソッドは澤山ある。self はインスタンス自身を返すメソッド。
zone は先述の NSZone を作つて返すメソッド。これは allocWithZone、copyWithZone といつたやうなクラスメソッドなどの引數となる。
performSelector は SEL、IMP、Methodの三つの型を理解する爲に擧げた。一部の例が Ruby で申し訣ないが、次のやうな物である
- SEL型:セレクタ。C の構造體のポインタ型(Opaque、實態はchar型)。Ruby だと Symbol クラス。
- IMP型:メソッドの實裝。C の函數ポインタ。Ruby だと Proc クラスなどか。
- Method型:メソッド。C の構造體で、SEL型・IMP型・char型を格納する。
### objc-class.h typedef struct objc_method *Method; struct objc_method { SEL method_name; char *method_types; IMP method_imp; }; ### objc.h typedef struct objc_selector *SEL; typedef id (*IMP)(id, SEL, ...); ### performSelector は次のやうに使ふ(self メソッドを呼ぶ) SEL *aSelector = @selector(:self); # @selector は ObjC の言語構造である # なほこれらの@で始まるこれらの文字をコンパイラへの「ディレクティブ」と呼び、他にも幾つかある。 SEL *aSelector = NSSelectorFromString(@"self"); # この定義濟函數でNSString から SEL に變換できる。 # 同樣に@"string" はディレクティブであり、呼出したモヂュール内部での NSString のオブジェクト定數となる。 [obj performSelector: aSelector]; # 送信先からの戻り値を返す。id 型なので何でもアリ。 NSString *method = NSStringFromSelector(aSelector); # この定義濟函數で SEL から NSString に變換できるisProxy が NSObject Protocol に態〻定義されてゐるのは、NSProxy クラスがルートクラスだからである。NSProxy は NSObject Protocol を實裝するけれども、他のクラスと異なり NSObject を繼承しない。クラスとプロトコルの違ひを強調する爲に項を割いた。
Cocoa基礎ガイド > Cocoaオブジェクト > オブジェクトの作成
Objective-C 2.0プログラミング言語 >ランタイムシステム > オブジェクトの割り当てと初期化
Objective-C 2.0プログラミング言語 > クラス
Objective-C 2.0プログラミング言語 > メッセージングの仕組み
Objective-C 2.0プログラミング言語 > 付録 A: 言語の要約 > コンパイラのディレクティブ
マイコミの「ダイナミックObjective-C」コラム。オブジェクトについては14~17あたりをみてほしい。メソッドについては18~22。GC については96~100。
Cocoaプログラミングの話題。Cocoaのメモリ管理など參照。
かんたんObjective-C
Foundation クラスの最適化
Cocoa では次のコレクションが用意される。繼承關係も示した
NSArray は配列、NSDictionary は辭書(ハッシュ)、NSSet は集合(聚合、重複を許さぬ配列)です。このクラスに格納したオブジェクトは變更することができない(Immutable)。變更すること(Mutable)を望む場合は次のクラスを使用する。
またコレクションは次のプロトコルを實裝する。
NSFastEnumeration は Objective-C 2.0 より實裝された高速列擧(Leopard 以降)のためのもので次の表記が可能になる。
for(id objectItem in array){ .... }
NSCopying、NSMutableCopying は複製するためのプロトコル。NSObject に複製用メソッドは定義されてゐるものの、NSObject はこのプロトコルに關しては實裝してゐない。
### NSObject Class: Tasks - copy + copyWithZone - mutableCopy + mutableCopyWithZone ### NSArray, NSDictionary, NSSet: Adopted Protocol ## NSCopying Protocol - copyWithZone ## NSMutableCopying Protocol - mutableCopyWithZone
Objective-C 2.0プログラミング言語 > 高速列挙
一方で次のやうなデータ型的な物がある。Primitive とあるやうに基本である Foundation の更に基本構成員たちである。
更に次のやうな型が定義される。これは C の構造體といふ位置づけになる。
NSRange は特に Foundation に於いて頻出である。これら構造體は CGFloat、NSUInteger などの型を格納する。そんなにややこしいものでもないので「Foundation Data Types Reference」及びヘッダファイルより拔萃。
typedef struct _NSPoint { CGFloat x; CGFloat y; } NSPoint; typedef struct _NSRect { NSPoint origin; NSSize size; } NSRect; typedef struct _NSSize { CGFloat width; CGFloat height; } NSSize; typedef struct _NSRange { NSUInteger location; NSUInteger length; } NSRange; #if __LP64__ typedef long NSInteger; typedef unsigned long NSUInteger; #else typedef int NSInteger; typedef unsigned int NSUInteger; endif
NSUInteger は 64bit な Mac と 32bit な Mac に於いての工夫を施すために定義された型となる(註:つまりvoid *、ポインタと同じ大きさ)。
//CGBase.h typedef float CGFloat;// 32-bit typedef double CGFloat;// 64-bit
CGFloat 型は「CGGeometry Reference(CGBase.h)」に説明があるけれども、要するにfloat(double)型である。これらを列擧した理由は NSValue がサポートする物だからに他ならない。NSValue がサポートできる型の値は KVC の自動ラッピング機構を利用できる。
また次の定義濟函數で各々の型を作ることができる。
NSMakePoint(x, y) NSMakeRect(origin,size) NSMakeSize(width, height) NSMakeRange(location, length)
本家本元のAppleによる 「Objective-C プログラミング言語」の解説。
ダイナミックObjective-C(マイコミジャーナル・コラム)。Cocoa での Objective-C がいかに動的な工夫があるか、いかにデザインパターンを實裝するかを綴る。