もう1つの編集:
コメントの質問に答えるには:
スレッド間で情報を渡すためにどの IPC メカニズムが使用されていますか? 共有メモリ?ソケット?マッハのメッセージ?
NSThread はメイン スレッドへの参照を内部的に格納し、その参照を介してそのスレッドの NSRunloop への参照を取得できます。NSRunloop は内部的にリンクされたリストであり、NSTimer オブジェクトをランループに追加することによって、新しいリンクされたリスト要素が作成され、リストに追加されます。したがって、実際にはメイン スレッドに属しているリンク リストは、別のスレッド内から単純に変更された共有メモリであると言えます。リンクされたリストの編集がスレッドセーフであることを確認するミューテックス/ロック (おそらく NSLock オブジェクトでさえも) があります。
擬似コード:
// Main Thread
for (;;) {
lock(runloop->runloopLock);
task = NULL;
do {
task = getNextTask(runloop);
if (!task) {
// function below unlocks the lock and
// atomically sends thread to sleep.
// If thread is woken up again, it will
// get the lock again before continuing
// running. See "man pthread_cond_wait"
// as an example function that works
// this way
wait_for_notification(runloop->newTasks, runloop->runloopLock);
}
} while (!task);
unlock(runloop->runloopLock);
processTask(task);
}
// Other thread, perform selector on main thread
// selector is char *, containing the selector
// object is void *, reference to object
timer = createTimerInPast(selector, object);
runloop = getRunloopOfMainThread();
lock(runloop->runloopLock);
addTask(runloop, timer);
wake_all_sleeping(runloop->newTasks);
unlock(runloop->runloopLock);
もちろん、これは単純化しすぎており、ほとんどの詳細はここでは関数間に隠されています。たとえば、getNextTask は、タイマーが既に起動している必要がある場合にのみ、タイマーを返します。すべてのタイマーの起動日がまだ未来であり、処理する他のイベント (UI からのキーボード、マウス イベント、または送信された通知など) がない場合、NULL が返されます。
私はまだ質問が何であるかわかりません。セレクターは、呼び出されるメソッドの名前を含む C 文字列にすぎません。すべてのメソッドは通常の C 関数であり、メソッド名を文字列および関数ポインタとして含む文字列テーブルが存在します。これは、Objective-C が実際にどのように機能するかの非常に基本的なものです。
以下に書いたように、ターゲット オブジェクトへのポインターとメソッド名を含む C 文字列へのポインターを取得する NSTimer オブジェクトが作成され、タイマーが起動すると、文字列テーブルを使用して呼び出す正しい C メソッドを見つけます (したがって、メソッドの文字列名が必要です) ターゲットオブジェクトの (したがって、それへの参照が必要です)。
正確には実装ではありませんが、それにかなり近いです:
Cocoa のすべてのスレッドには NSRunLoop があります (常にそこにあり、スレッドを作成する必要はありません)。PerformSelectorOnMainThread は、このような NSTimer オブジェクトを作成します。これは、一度だけ起動し、起動する時間がすでに過去にある場合 (したがって、すぐに起動する必要があります)、メイン スレッドの NSRunLoop を取得し、そこにタイマー オブジェクトを追加します。メインスレッドがアイドル状態になるとすぐに、Runloop で処理する次のイベントを検索し (または、処理するものが何もない場合はスリープ状態になり、イベントが追加されるとすぐに再び起動されます)、それを実行します。呼び出しをスケジュールするときにメインスレッドがビジーである場合、現在のタスクが終了するとすぐにタイマーイベントを処理するか、現在スリープ状態である場合、イベントを追加することによって起動されますそしてすぐに処理します。
Apple がどのようにそれを行っている可能性が最も高いかを調べるための良い情報源(クローズド ソースであるため、誰も確実に言うことはできません) は GNUStep です。GCC は Objective-C を処理できるため (これは Apple が出荷する単なる拡張ではなく、標準の GCC でさえ処理できます)、しかし、Apple が出荷するすべての基本クラスなしで Obj-C を使用することはかなり役に立たないため、GNU コミュニティは再試行しようとしました。 - Mac で使用する最も一般的な Obj-C クラスを実装し、それらの実装は OpenSource です。
ここでは、最近のソース パッケージをダウンロードできます。
それを解凍し、詳細については NSThread、NSObject、および NSTimer の実装を見てください。おそらく Apple は gdb を使ってそれを証明できると思いますが、なぜ彼らはそのアプローチと大きく違うことをするのでしょうか? それは非常にうまく機能する巧妙なアプローチです:)