41
第13回iPhone輪講 やるしかない!

Objc04

Embed Size (px)

Citation preview

Page 1: Objc04

第13回iPhone輪講やるしかない!

Page 2: Objc04

クラスとインスタンス

NSObjectのメソッドはNSObject自体に対して使われるというより,そのサブクラスである,あらゆるクラスおよびインスタンスで共通して使われる

Page 3: Objc04

クラスとインスタンス

- (Class)class

レシーバに属するクラスのクラスオブジェクトを返す

+ (Class)class

クラスオブジェクトを返す

クラスオブジェクトを他のメッセージの引数としたり変数に代入する場合はこのクラスメソッドを使う

- (id)self

レシーバ自体を返す

Page 4: Objc04

クラスとインスタンス

- (BOOL)isMemberOfClass:(Class)aClass

レシーバが引数のクラスのインスタンスかどうか調べる

- (BOOL)isKindIfClass:(Class)aClass

レシーバが引数のクラスのインスタンスか,あるいはそのクラスのサブクラスのインスタンスかどうかを調べる

+ (BOOL)isSubclassOfClass:(Class)aClass

レシーバが引数のクラスのサブクラスか,その自体である場合にYESを返す

Page 5: Objc04

クラスとインスタンス

- (Class)superclass

レシーバの属するクラスのスーパークラスのクラスオブジェクトを返す

+ (Class)superclass

レシーバのスーパークラスのクラスオブジェクトを返す

Page 6: Objc04

インスタンスの生成と解放

+ (id)alloc

レシーバとして指定されたクラスのインスタンスを生成します

常にイニシャライザと組み合わせて用いる必要がある

- (void)dealloc

インスタンスを解放する

このメソッドはreleaseの結果として呼び出される

Page 7: Objc04

インスタンスの生成と解放

- (oneway void)release

レシーバのリファレンスカウンタを1つ減らす

リファレンスカウンタが0になると,deallocメソッドが呼び出され,レシーバが解放される

- (id)retain

レシーバのリファレンスカウンタを1つ増やし,レシーバ自体を返す

Page 8: Objc04

インスタンスの生成と解放

- (id)autorelease

レシーバを現在有効な自動解放プールに追加し,レシーバ自体を返す

- (NSUInteger)retainCount

レシーバのリファレンスカウンタを値として返す

デバッグ用

NSUIntegerは符号なし整数

Page 9: Objc04

インスタンスの生成と解放

- (void)finalize

ガーベジコレクションがレシーバを解放する直前に実行

Page 10: Objc04

初期化

- (id)init

allocで生成されたインスタンスを初期化する

サブクラスではinitを上書きするか,新たなイニシャライザinit...という名前で定義して初期化を行う

+ (void)initialize

クラスの初期化(クラス内で共通に使われる変数の初期設定などを行う)に利用する

そのクラスに対して送られる初めてのメッセージに先立って自動的に実行される

Page 11: Objc04

初期化

+ (id)new

一般にはallocとinitの呼び出しを組み合わせたもの

newメソッドで返されるインスタンスのオーナーは呼び出し側のオブジェクトになる

Page 12: Objc04

オブジェクトの比較

- (BOOL)isEqual:(id)anObject

レシーバと引数anObjectが等しいと判断される場合YESを返す

原則としてオブジェクトへの同じポインタを持つものは等しいと見なされる

サブクラスは加えて「同じ値を持つもの」を等しいと判断するように定義が拡張されていることがある

Page 13: Objc04

オブジェクトの比較

比較のためのメソッドとしてcompare:やisEqualto...という,そのクラス特有の比較メソッドを持っていることもある

どのメソッドを利用したらよいのか,目的に応じて考える必要がある

Page 14: Objc04

オブジェクトの内容記述

+ (NSString *)deacription

レシーバのクラスの内容を表すNSStringの文字列を返す

通常はクラス名が返される

- (NSString *)description

レシーバのインスタンスオブジェクトの内容を表す

通常はクラス名とid値を表示するが,サブクラスによって独自の定義をする事もある

Page 15: Objc04

セレクタとSEL型

プログラム内で,メソッド宣言やメッセージ式として書かれたセレクタは,コンパイル時に内部表現の値に変換される

この内部表現に対応するデータ型をSEL型と呼ぶ

Page 16: Objc04

セレクタとSEL型

ObjCではセレクタの内部表現をプログラムで扱えるようにプログラム上のセレクタの表記からSEL型データを得るコンパイラ指示子@selector()が用意されている

@selector(mutableCopy);@selector(compare:)@selector(replaceobjectAtIndex:WithObject:)

Page 17: Objc04

セレクタとSEL型

セレクタが異なれば対応するSEL型も異なり,同じセレクタには必ず同じSEL型の値が対応する

SEL型の変数が有効なセレクタを値として持っていない事を表したい場合

NULLを使うか,(SEL)0という表現を使う

Page 18: Objc04

セレクタとSEL型

SEL型の値を使ってメッセージを送信できる

- (id)performSelector:(SEL)aSelector

aSelectorの示すメッセージをレシーバに送信しその結果を返す

- (id)performSelector:(SEL)aSelector withObject:(id)anObject

aSelectorの示すメッセージを,anObjectを引数としてレシーバに送信し,その結果を返す

Page 19: Objc04

メッセージ探索

すべてのインスタンスにはisaというClass型のインスタンス変数が存在している

これがクラスオブジェクトを示している

Page 20: Objc04

メッセージ探索

まずランタイムシステムは,メッセージと同じセレクタを持つメソッドがこのクラス内に存在するか調べる

存在すればそのメソッドを実行する

存在しなければ,スーパークラスを辿って行ってメソッドが存在するか調べる

ルートクラスにまでさかのぼっても目的のメソッドが発見できなかった場合,実行時エラーが発生する

Page 21: Objc04

メッセージ探索

ランタイムシステムは,あるクラスがどのセレクタに対応するメソッドを持っていて,その定義の場所はどこか,という情報を内部的にキャッシュとして蓄えている

次に同じメッセージが送られたときには,キャッシュの情報を利用して,探索を繰り返す必要がないようにする

Page 22: Objc04

メッセージ探索

あるオブジェクトが指定したセレクタに対応したメソッドを実装しているかどうか,動的に調べる事が出来る

aSelectorの示すメッセージを処理できるメソッドがレシーバに実装されているか,継承されていればYESを返す

レシーバとなるクラスがaSelectorの示すメッセージを処理できるインスタンスメソッドを実装しているか継承していればYESを返す

- (BOOL)respondsToSelector:(SEL)aSelector

- (BOOL)instancesRespondToSelector:(SEL)aSelector

Page 23: Objc04

selfへの代入

selfはメッセージを受け取ったオブジェクト自体を表す

それ自体に再度メッセージを送ったり,メッセージの引数やメソッドの返り値として使う事が出来る

Page 24: Objc04

selfの代入

selfに値を代入するという使い方がある

イニシャライザの定義内では,スーパークラスのイニシャライザの返り値をselfに代入する書き方を示した

- (id)initWithMax:(int)a{ if ((self = [super init]) == nil) { max = a; } return self;}

Page 25: Objc04

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

クラスオブジェクトもオブジェクトなので,ルートクラスであるNSObjectを継承したクラスの「インスタンスとして」振る舞う

Page 26: Objc04

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

次のような式を実行するとYESが返される

このことはクラスオブジェクトに相当するオブジェクトが存在している事を示している

クラスオブジェクトのクラスの事をメタクラスと呼ぶ

ObjCではプログラムでメタクラスを扱う事は無い

[[NSString class] isKindOfClass:[NSObject class]]

Page 27: Objc04

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

SEL型を用いれば,実行されるメソッドを動的に変更する事が可能

Applicationフレームワークでは実際に,この仕組みを用いてGUI部品間のメッセージ送受信を実現している

Page 28: Objc04

ターゲット-アクション・パラダイム

このクラスはSEL型変数actionid型変数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

Page 29: Objc04

ターゲット-アクション・パラダイム

このクラスのインスタンスに対して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

Page 30: Objc04

ターゲット-アクション・パラダイム

このときの引数は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

Page 31: Objc04

ターゲット-アクション・パラダイム

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

Page 32: Objc04

ターゲット-アクション・パラダイム

Applicationフレームワークのターゲット-アクション・パラダイムで,メッセージとして使われるのは次のようにid型の引数を1つだけ持ち,返り値の無い形式のメソッドだけ

この形式のメソッドをアクションメソッドと呼ぶ

- (void) XXXXXXX : (id)sender;

Page 33: Objc04

- (void) XXXXXXX : (id)sender;- (void) XXXXXXX : (id)sender;

Customize...

obj

id target obj

SEL action showPanel

[button setTarget:obj];[button setAction:@selector          (showpanel:)];

showPanel : buttonbutton クリックでメッセージ送信

参照

ターゲット-アクション・パラダイム

ボタンが押されたり,スライダが動かされた時あらかじめ設定されたtargetに,actionで指定されたメッセージが送られる

Page 34: Objc04

- (void) XXXXXXX : (id)sender;- (void) XXXXXXX : (id)sender;

Customize...

obj

id target obj

SEL action showPanel

[button setTarget:obj];[button setAction:@selector          (showpanel:)];

showPanel : buttonbutton クリックでメッセージ送信

参照

ターゲット-アクション・パラダイム

メッセージの引数にはそのGUI部品のidが渡される

Page 35: Objc04

- (void) XXXXXXX : (id)sender;- (void) XXXXXXX : (id)sender;

Customize...

obj

id target obj

SEL action showPanel

[button setTarget:obj];[button setAction:@selector          (showpanel:)];

showPanel : buttonbutton クリックでメッセージ送信

参照

ターゲット-アクション・パラダイム

これによりtargetとして指定されたオブジェクトでは,どの部品からどのようなメッセージを送られたのか知る事が出来る

Page 36: Objc04

- (void) XXXXXXX : (id)sender;- (void) XXXXXXX : (id)sender;

Customize...

obj

id target obj

SEL action showPanel

[button setTarget:obj];[button setAction:@selector          (showpanel:)];

showPanel : buttonbutton クリックでメッセージ送信

参照

ターゲット-アクション・パラダイム

通常はターゲットとアクションの指定にそれぞれメッセージsetTarget:とsetAction:が使われる

カウンタ方式を利用している場合でも,setTarget:は引数のオブジェクトを保持(retain)しない

Page 37: Objc04

ターゲット-アクション・パラダイム

Interface Builderで自動生成されるObjective-Cのソースコードには,アクションメソッドは以下のように定義される

IBActionはマクロでvoidに定義される

- (IBAction) XXXXXXX : (id)sender;

Page 38: Objc04

ターゲット-アクション・パラダイム

オブジェクトのインスタンス変数のうち,GUI部品や他のオブジェクトを参照するためにInterface Builderで利用されるものはアウトレットと呼ばれる

Page 39: Objc04

ターゲット-アクション・パラダイム

Interface Builderがソースコードを自動生成した場合

例えばNSButton型の部品を参照するためのインスタンス変数の宣言は以下のようになる

IBOutlet NSButton *theButton;

Page 40: Objc04

ターゲット-アクション・パラダイム

IBOutletもマクロで何も無い空白として定義される

IBOutoletはInterface Builderに対する目印として使われている

Interface Builderはid型のインスタンス変数もアウトレットとみなす

Page 41: Objc04

おわり