完全なC互換。CocoaはObjective-CのAPI。Cocoaについて学べば必然的にObjective-Cについて学べます。主な開発環境はXcode(または旧Project Builder)。プログラミング言語
一般的な Object 指向の思想を理解してゐる前提の元に文法事項を解説します。
定義は.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 等である。
今先程のクラスに、インスタンス變數 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 に於て記述する。更にこの MyObject のインスタンスを保持した變數 receiver が存在したとすれば、二つのメソッドを呼出すには、
[MyObject myClassMethod];
[receiver myMethod];
と書く。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: の如きメソッド名の樣にみえる表記はラベルを表してゐたに過ぎない。つまりレシーバに引數を送信する爲には必ずラベルをつけたメッセージを送る事になるわけ。この事實は命名の仕方にある程度關聯するので留意されたい。
Objective-C では、nil に存在しないメッセージを送信しても、エラーが發生しません。これは通常のレシーバでは致命的なエラーとなる事と異なる結果を導くので注意して下さい。
[nil myMethod];//エラーにならない [receiver myMethod2];//myMethod2が無ければエラー
これは譬へば delegate で nil を設定しても呼出しに惱む必要がない等、ただメッセージを送信するだけの用途のコードのエラー處理を短縮する事になるでせう。
NSObject Protocol として NSObject に實裝されてゐる +alloc、-init、-retain、-release、-autorelease、そして NSAutoreleasePool class を解説します。
Xcode は Apple による工夫によつて擧動に「癖」がある。
API はよく遣ふ物を特に説明する。ただし Core Data については割愛する。
Objective-C のコンパイラは完全な C 互換を提供する大變すぐれたオブジェクト指向言語。動的型による「クラス型オブジェクト指向ランタイム」。現在に於いて言語仕樣イコールアップルと思へばよい程に、アップルがこの仕樣を擴張して居る。
NeXTstep が OPENSTEP といふ OS の開發環境として採用し、それが Mac OS X として採用されたため、Mac OS X での主な開發環境は Objective-C となつて居る。C++ の比べてややマイナー。C++ は Mac OS X に於いては USB ドライバだとか IO Kit 系で使ふことがあるらしい。
Cocoa の實裝は Java に影響を與へた。 Smalltalk といふ氣持ち惡い言語の概念に多く影響を受けて居る。
ディレクティブてのはソース内部でコンパイラ及びプリプロセッサが理解する恰もコマンドが如き類ひである。ソースコードを讀み書きする前に理解しておきたい。
Objective-C では C のプリプロセッサに次の擴張を施した
#import は #include と同じだが、一度しか讀み込まない。// は行末迄コメントと解する。
Objective-C では C のプリプロセッサに次の擴張を施した。必ず "@" から始まる。
これらはクラス、カテゴリ、プロトコルを宣言する手段である。@end で宣言を閉ぢる。詳しくは後述。
インスタンス變數の可視性は次の宣言で示す。初期設定は@protectedである。
例外処理は次をサポートする。@finally が強制實行部位で、あとはお馴染みか。
更に特定の目的が爲、次が用意される。
詳しくは要約として次に用意されてゐる。構文もまた參照せよ。
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 がいかに動的な工夫があるか、いかにデザインパターンを實裝するかを綴る。