[解決済み] NSObject +loadと+initialize - これらは何をするのですか?
質問
私は、開発者が +initialize または +load をオーバーライドする状況を理解することに興味があります。ドキュメントでは、これらのメソッドが Objective-C ランタイムによって呼び出されることは明らかですが、これらのメソッドのドキュメントから明らかなのは、本当にそれだけです。)
私の好奇心は、Apple のサンプルコードである MVCNetworking を見たことから来ました。彼らのモデル クラスには
+(void) applicationStartup
メソッドを持っています。これは、ファイルシステム上でいくつかのハウスキーピングを行い、NSDefaults を読み取ります。
私は MVCNetworking プロジェクトを修正し、App Delegate の +applicationStartup への呼び出しを削除し、掃除のビットを +load に入れました。私は、+load または +initialize に対して呼び出さなければならないカスタム セットアップ メソッドに関する微妙な点、gotchas、および whatnots について理解を得ることを望んでいます。
For +load ドキュメントにはこうあります。
loadメッセージはクラスとカテゴリに送られます。 動的にロードされ、静的にリンクされたクラスとカテゴリに送られます。 クラスまたはカテゴリが応答することができるメソッドを実装している場合にのみ送信されます。
この文章は、すべての単語の正確な意味を知らなければ、解析するのが困難なクドイ文章です。助けてください。
-
動的ロードと静的リンクの両方とはどういう意味ですか。
-
新しく読み込まれたクラスまたはカテゴリは、応答することができるメソッドを実装しています。どのように応答するのですか?
+initializeについては、ドキュメントに書かれています。
initializeはクラスごとに一度だけ実行されます。もし クラスと、そのクラスのカテゴリに対して独立した初期化を行いたい場合は のカテゴリに対して独立した初期化を行いたい場合は、loadメソッドを実装する必要があります。
これは、"クラスを設定しようとしている場合... initialize."を使用しないでください、という意味だと解釈しています。では、いつ、なぜ、initializeをオーバーライドするのでしょうか?
どのように解決するのですか?
その
load
メッセージ
ランタイムが送信する
load
メッセージを各クラスオブジェクトに送ります。クラスオブジェクトがプロセスのアドレス空間にロードされるとすぐにです。 プログラムの実行可能ファイルの一部であるクラスに対して、ランタイムは
load
メッセージを送信します。 共有(動的にロードされる)ライブラリにあるクラスについては、ランタイムは共有ライブラリがプロセスのアドレス空間にロードされた直後にロードメッセージを送信します。
さらに、ランタイムは
load
をクラスオブジェクトに送るのは、そのクラスオブジェクト自身が
load
メソッドを実装している場合、そのクラスオブジェクトに 例
@interface Superclass : NSObject
@end
@interface Subclass : Superclass
@end
@implementation Superclass
+ (void)load {
NSLog(@"in Superclass load");
}
@end
@implementation Subclass
// ... load not implemented in this class
@end
ランタイムは
load
メッセージに
Superclass
クラスオブジェクトに送信します。 それは
ではなく
を送信します。
load
メッセージに
Subclass
クラスオブジェクトに、たとえ
Subclass
からメソッドを継承していても
Superclass
.
ランタイムは
load
を送信した後、クラスオブジェクトに
load
メッセージを送信した後 (そのスーパークラスのオブジェクトが
load
を実装している場合)、およびリンク先の共有ライブラリのすべてのクラス・オブジェクトにメッセージを送信します。 しかし、自分の実行ファイル内の他のどのクラスが
load
を受け取ったかどうかはわかりません。
あなたのプロセスがそのアドレス空間にロードするすべてのクラスは、そのアドレス空間に
load
を実装している場合、そのクラスは
load
メソッドを実装していれば、プロセスがそのクラスを他に利用するかどうかに関わらず
ランタイムがどのように
load
メソッドの中で特別なケースとして
_class_getLoadMethod
の
objc-runtime-new.mm
から直接呼び出す。
call_class_loads
で
objc-loadmethod.mm
.
また、ランタイムは
load
を実装している同じクラスの複数のカテゴリであっても、 ロードするすべてのカテゴリの load
. これは珍しいことです。 通常、2つのカテゴリが同じクラスで同じメソッドを定義した場合、1つのメソッドが「勝って」使用され、もう1つのメソッドは決して呼び出されることはないでしょう。
は
initialize
メソッド
ランタイムは
initialize
メソッドをクラスオブジェクトに呼び出します(最初のメッセージを送信する直前の
load
または
initialize
) をクラスオブジェクトやクラスのインスタンスに送信します。 このメッセージは通常のメカニズムで送信されるので、もしあなたのクラスが
initialize
を実装しておらず、実装しているクラスを継承している場合、 あなたのクラスはそのスーパークラスの
initialize
. ランタイムは
initialize
をクラスのスーパークラス全てに送ります (スーパークラスがまだ
initialize
).
例
@interface Superclass : NSObject
@end
@interface Subclass : Superclass
@end
@implementation Superclass
+ (void)initialize {
NSLog(@"in Superclass initialize; self = %@", self);
}
@end
@implementation Subclass
// ... initialize not implemented in this class
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
Subclass *object = [[Subclass alloc] init];
}
return 0;
}
このプログラムは2行の出力を行います。
2012-11-10 16:18:38.984 testApp[7498:c07] in Superclass initialize; self = Superclass
2012-11-10 16:18:38.987 testApp[7498:c07] in Superclass initialize; self = Subclass
システムは
initialize
メソッドを遅延して送信するため、プログラムが実際にクラス (またはサブクラス、あるいはクラスやサブクラスのインスタンス) にメッセージを送信しない限り、クラスはメッセージを受信しません。 そして、受信するまでに
initialize
を受け取る頃には、あなたのプロセス内のすべてのクラスはすでに
load
を受け取っているはずです (適切であれば)。
を実装する標準的な方法は
initialize
はこうです。
@implementation Someclass
+ (void)initialize {
if (self == [Someclass class]) {
// do whatever
}
}
このパターンのポイントは
Someclass
を実装していないサブクラスがある場合、それ自体を再初期化することを避けるためです。
initialize
.
ランタイムは
initialize
メッセージを
_class_initialize
関数で
objc-initialize.mm
. を使用していることがわかります。
objc_msgSend
を使って送信していることがわかります。これは通常のメッセージ送信機能です。
さらに読む
チェックアウト マイク・アッシュの金曜日のQ&A をご覧ください。
関連
-
[解決済み] アトミック属性と非アトミック属性の違いは何ですか?
-
[解決済み] Objective-Cのtypedef enumとは何ですか?
-
[解決済み] Objective-Cで配列に結合する
-
[解決済み] 角括弧 < > と引用符 " " を使って #import する。
-
[解決済み] Objective-CのクラスでSwiftのプロトコルをインポートする
-
[解決済み] Objective-Cです。カテゴリ内のプロパティ/インスタンス変数
-
[解決済み] iOSの合成されたプロパティの名前を、先頭のアンダースコアで変更するのはなぜですか?重複
-
[解決済み] Objective-Cのセレクタ?
-
[解決済み] キューに入れられたperformSelector:afterDelayの呼び出しをキャンセルする
-
[解決済み] ベストプラクティス - 自分のプロジェクト/アプリのためのNSErrorドメインとコード
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 現在の日付から7日分を差し引いた日数
-
[解決済み] Objective-Cのクラス→文字列のようなものです。[NSArray className] -> @"NSArray" のようになります。
-
[解決済み] Objective-Cで配列に結合する
-
[解決済み] 角括弧 < > と引用符 " " を使って #import する。
-
[解決済み] Xcodeはクラッシュの原因となる行を表示しない
-
[解決済み] RootViewControllerのスイッチングアニメーション
-
[解決済み] 複数のサブクラスで1つのストーリーボードuiviewcontrollerを使用する方法
-
[解決済み] なぜObjective-Cはプライベートメソッドをサポートしないのですか?
-
[解決済み] キューに入れられたperformSelector:afterDelayの呼び出しをキャンセルする
-
[解決済み] IOSのUIViewからアプリケーションのドキュメントフォルダに画像を保存する