第13回iPhone輪講
やるしかない!
クラスとインスタンス
NSObjectのメソッドはNSObject自体に対して使われるとい
うより,そのサブクラスである,あらゆるクラスおよび
インスタンスで共通して使われる
クラスとインスタンス
- (Class)class
レシーバに属するクラスのクラスオブジェクトを返す
+ (Class)class
クラスオブジェクトを返す
クラスオブジェクトを他のメッセージの引数としたり
変数に代入する場合はこのクラスメソッドを使う
- (id)self
レシーバ自体を返す
クラスとインスタンス
- (BOOL)isMemberOfClass:(Class)aClass
レシーバが引数のクラスのインスタンスかどうか調べる
- (BOOL)isKindIfClass:(Class)aClass
レシーバが引数のクラスのインスタンスか,あるいは
そのクラスのサブクラスのインスタンスかどうかを調べる
+ (BOOL)isSubclassOfClass:(Class)aClass
レシーバが引数のクラスのサブクラスか,その自体である
場合にYESを返す
クラスとインスタンス
- (Class)superclass
レシーバの属するクラスのスーパークラスのクラスオブ
ジェクトを返す
+ (Class)superclass
レシーバのスーパークラスのクラスオブジェクトを返す
インスタンスの生成と解放
+ (id)alloc
レシーバとして指定されたクラスのインスタンスを生成し
ます
常にイニシャライザと組み合わせて用いる必要がある
- (void)dealloc
インスタンスを解放する
このメソッドはreleaseの結果として呼び出される
インスタンスの生成と解放
- (oneway void)release
レシーバのリファレンスカウンタを1つ減らす
リファレンスカウンタが0になると,deallocメソッドが
呼び出され,レシーバが解放される
- (id)retain
レシーバのリファレンスカウンタを1つ増やし,
レシーバ自体を返す
インスタンスの生成と解放
- (id)autorelease
レシーバを現在有効な自動解放プールに追加し,
レシーバ自体を返す
- (NSUInteger)retainCount
レシーバのリファレンスカウンタを値として返す
デバッグ用
NSUIntegerは符号なし整数
インスタンスの生成と解放
- (void)finalize
ガーベジコレクションがレシーバを解放する直前に実行
初期化
- (id)init
allocで生成されたインスタンスを初期化する
サブクラスではinitを上書きするか,新たなイニシャライ
ザinit...という名前で定義して初期化を行う
+ (void)initialize
クラスの初期化(クラス内で共通に使われる変数の初期設
定などを行う)に利用する
そのクラスに対して送られる初めてのメッセージに
先立って自動的に実行される
初期化
+ (id)new
一般にはallocとinitの呼び出しを組み合わせたもの
newメソッドで返されるインスタンスのオーナーは
呼び出し側のオブジェクトになる
オブジェクトの比較
- (BOOL)isEqual:(id)anObject
レシーバと引数anObjectが等しいと判断される場合YESを
返す
原則としてオブジェクトへの同じポインタを持つものは
等しいと見なされる
サブクラスは加えて「同じ値を持つもの」を等しいと
判断するように定義が拡張されていることがある
オブジェクトの比較
比較のためのメソッドとしてcompare:や
isEqualto...という,そのクラス特有の比較メソッド
を持っていることもある
どのメソッドを利用したらよいのか,
目的に応じて考える必要がある
オブジェクトの内容記述
+ (NSString *)deacription
レシーバのクラスの内容を表すNSStringの文字列を返す
通常はクラス名が返される
- (NSString *)description
レシーバのインスタンスオブジェクトの内容を表す
通常はクラス名とid値を表示するが,サブクラスによって
独自の定義をする事もある
セレクタとSEL型
プログラム内で,メソッド宣言やメッセージ式として書かれた
セレクタは,コンパイル時に内部表現の値に変換される
この内部表現に対応するデータ型をSEL型と呼ぶ
セレクタとSEL型
ObjCではセレクタの内部表現をプログラムで扱えるように
プログラム上のセレクタの表記からSEL型データを得る
コンパイラ指示子@selector()が用意されている
@selector(mutableCopy);
@selector(compare:)
@selector(replaceobjectAtIndex:WithObject:)
セレクタとSEL型
セレクタが異なれば対応するSEL型も異なり,
同じセレクタには必ず同じSEL型の値が対応する
SEL型の変数が有効なセレクタを値として持っていない事を
表したい場合
NULLを使うか,(SEL)0という表現を使う
セレクタとSEL型
SEL型の値を使ってメッセージを送信できる
- (id)performSelector:(SEL)aSelector
aSelectorの示すメッセージをレシーバに送信し
その結果を返す
- (id)performSelector:(SEL)aSelector
withObject:(id)anObject
aSelectorの示すメッセージを,anObjectを引数として
レシーバに送信し,その結果を返す
メッセージ探索
すべてのインスタンスにはisaというClass型のインスタンス変
数が存在している
これがクラスオブジェクトを示している
メッセージ探索
まずランタイムシステムは,メッセージと同じセレクタを持つ
メソッドがこのクラス内に存在するか調べる
存在すればそのメソッドを実行する
存在しなければ,スーパークラスを辿って行ってメソッドが
存在するか調べる
ルートクラスにまでさかのぼっても目的のメソッドが発
見できなかった場合,実行時エラーが発生する
メッセージ探索
ランタイムシステムは,あるクラスがどのセレクタに対応する
メソッドを持っていて,その定義の場所はどこか,
という情報を内部的にキャッシュとして蓄えている
次に同じメッセージが送られたときには,キャッシュの
情報を利用して,探索を繰り返す必要がないようにする
メッセージ探索
あるオブジェクトが指定したセレクタに対応したメソッドを
実装しているかどうか,動的に調べる事が出来る
aSelectorの示すメッセージを処理できるメソッドが
レシーバに実装されているか,継承されていれば
YESを返す
レシーバとなるクラスがaSelectorの示すメッセージを
処理できるインスタンスメソッドを実装しているか
継承していればYESを返す
- (BOOL)respondsToSelector:(SEL)aSelector
- (BOOL)instancesRespondToSelector:(SEL)aSelector
selfへの代入
selfはメッセージを受け取ったオブジェクト自体を表す
それ自体に再度メッセージを送ったり,メッセージの
引数やメソッドの返り値として使う事が出来る
selfの代入
selfに値を代入するという使い方がある
イニシャライザの定義内では,スーパークラスのイニシャ
ライザの返り値をselfに代入する書き方を示した
- (id)initWithMax:(int)a
{
if ((self = [super init]) == nil) {
max = a;
}
return self;
}
クラスオブジェクトとルートクラス
クラスオブジェクトもオブジェクトなので,
ルートクラスであるNSObjectを継承したクラスの
「インスタンスとして」振る舞う
クラスオブジェクトとルートクラス
次のような式を実行するとYESが返される
このことはクラスオブジェクトに相当するオブジェクトが
存在している事を示している
クラスオブジェクトのクラスの事をメタクラスと呼ぶ
ObjCではプログラムでメタクラスを扱う事は無い
[[NSString class] isKindOfClass:[NSObject class]]
クラスオブジェクトとルートクラス
SEL型を用いれば,実行されるメソッドを動的に
変更する事が可能
Applicationフレームワークでは実際に,この仕組みを
用いてGUI部品間のメッセージ送受信を実現している
ターゲット-アクション・パラダイム
このクラスはSEL型変数action
id型変数targetをインスタンス
変数として持っている
@interface myCell : NSObject
{
SEL action;
id target;
...
}
- (void)setAction:(SEL)aSelector;
- (void)setTarget:(id)anObject;
- (void)performClick:(id)sender;
...
@end
@implementation myCell
- (void)setAction:(SEL)aSelector
{
action = aSelector;
}
- (void)setTarget:(id)anObject
{
target = anObject;
}
- (void)performClick:(id)sender
{
(void)[target performSelector:action
withObject:sender];
}
...
@end
ターゲット-アクション・パラダイム
このクラスのインスタンスに対
してperformClick:メッセージが
送られると,targetが
保持しているオブジェクトに
対してactionが表すメッセージ
が送られる
@interface myCell : NSObject
{
SEL action;
id target;
...
}
- (void)setAction:(SEL)aSelector;
- (void)setTarget:(id)anObject;
- (void)performClick:(id)sender;
...
@end
@implementation myCell
- (void)setAction:(SEL)aSelector
{
action = aSelector;
}
- (void)setTarget:(id)anObject
{
target = anObject;
}
- (void)performClick:(id)sender
{
(void)[target performSelector:action
withObject:sender];
}
...
@end
ターゲット-アクション・パラダイム
このときの引数は
performClick:の引数が使われる
@interface myCell : NSObject
{
SEL action;
id target;
...
}
- (void)setAction:(SEL)aSelector;
- (void)setTarget:(id)anObject;
- (void)performClick:(id)sender;
...
@end
@implementation myCell
- (void)setAction:(SEL)aSelector
{
action = aSelector;
}
- (void)setTarget:(id)anObject
{
target = anObject;
}
- (void)performClick:(id)sender
{
(void)[target performSelector:action
withObject:sender];
}
...
@end
ターゲット-アクション・パラダイム
Applicationフレームワークでは
このような原理でGUI部品
オブジェクト間の通信を
実現している
これを
ターゲット-アクション・
パラダイムと呼ぶ
@interface myCell : NSObject
{
SEL action;
id target;
...
}
- (void)setAction:(SEL)aSelector;
- (void)setTarget:(id)anObject;
- (void)performClick:(id)sender;
...
@end
@implementation myCell
- (void)setAction:(SEL)aSelector
{
action = aSelector;
}
- (void)setTarget:(id)anObject
{
target = anObject;
}
- (void)performClick:(id)sender
{
(void)[target performSelector:action
withObject:sender];
}
...
@end
ターゲット-アクション・パラダイム
Applicationフレームワークのターゲット-アクション
・パラダイムで,メッセージとして使われるのは
次のようにid型の引数を1つだけ持ち,返り値の無い形式の
メソッドだけ
この形式のメソッドをアクションメソッドと呼ぶ
- (void) XXXXXXX : (id)sender;
Customize...
obj
id target obj
SEL action showPanel
[button setTarget:obj];
[button setAction:@selector
          (showpanel:)];
showPanel : button
button クリックでメッセージ送信
参照
ターゲット-アクション・パラダイム
ボタンが押されたり,
スライダが動かされた時
あらかじめ設定された
targetに,actionで指定
されたメッセージが
送られる
Customize...
obj
id target obj
SEL action showPanel
[button setTarget:obj];
[button setAction:@selector
          (showpanel:)];
showPanel : button
button クリックでメッセージ送信
参照
ターゲット-アクション・パラダイム
メッセージの引数には
そのGUI部品のidが渡され
る
Customize...
obj
id target obj
SEL action showPanel
[button setTarget:obj];
[button setAction:@selector
          (showpanel:)];
showPanel : button
button クリックでメッセージ送信
参照
ターゲット-アクション・パラダイム
これによりtargetとして
指定されたオブジェクト
では,どの部品から
どのようなメッセージを
送られたのか知る事が出
来る
Customize...
obj
id target obj
SEL action showPanel
[button setTarget:obj];
[button setAction:@selector
          (showpanel:)];
showPanel : button
button クリックでメッセージ送信
参照
ターゲット-アクション・パラダイム
通常はターゲットとアク
ションの指定にそれぞれ
メッセージsetTarget:と
setAction:が使われる
カウンタ方式を利用
している場合でも,
setTarget:は引数の
オブジェクトを保持
(retain)しない
ターゲット-アクション・パラダイム
Interface Builderで自動生成されるObjective-Cの
ソースコードには,アクションメソッドは以下のように
定義される
IBActionはマクロでvoidに定義される
- (IBAction) XXXXXXX : (id)sender;
ターゲット-アクション・パラダイム
オブジェクトのインスタンス変数のうち,GUI部品や
他のオブジェクトを参照するためにInterface Builderで
利用されるものはアウトレットと呼ばれる
ターゲット-アクション・パラダイム
Interface Builderがソースコードを自動生成した場合
例えばNSButton型の部品を参照するための
インスタンス変数の宣言は以下のようになる
IBOutlet NSButton *theButton;
ターゲット-アクション・パラダイム
IBOutletもマクロで何も無い空白として定義される
IBOutoletはInterface Builderに対する目印として
使われている
Interface Builderはid型のインスタンス変数も
アウトレットとみなす
おわり

Objc04