Еще одна правка:
Чтобы ответить на вопрос комментария:
для чего используется механизм 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 вернет таймер, только если таймер уже должен был сработать. Если дата срабатывания для каждого таймера все еще в будущем и нет другого события для обработки (например, клавиатура, событие мыши из пользовательского интерфейса или отправленное уведомление), оно вернет NULL.
Я все еще не уверен, в чем вопрос. селектор - это не более чем строка C, содержащая имя вызываемого метода. Каждый метод представляет собой обычную функцию C, и существует таблица строк, содержащая имена методов в виде строк и указателей на функции. Это самые основные принципы работы Objective-C.
Как я писал ниже, создается объект NSTimer, который получает указатель на целевой объект и указатель на строку C, содержащую имя метода, и когда срабатывает таймер, он находит правильный метод C для вызова с использованием строки таблица (следовательно, ему нужно имя строки метода) целевого объекта (следовательно, ему нужна ссылка на него).
Не совсем реализация, но довольно близко к ней:
У каждого потока в Какао есть NSRunLoop (он всегда есть, вам никогда не нужно создавать поток для потока). PerformSelectorOnMainThread создает объект NSTimer, такой как this , который запускается только один раз и где время срабатывания уже находится в прошлом (поэтому он должен быть запущен немедленно), затем получает NSRunLoop основного потока и добавляет объект таймер там. Как только основной поток переходит на idle , он ищет следующее событие в своем Runloop для обработки (или переходит в спящий режим, если нечего обрабатывать, и снова просыпается, как только событие добавляется) и выполняет это. Либо основной поток занят, когда вы планируете вызов, и в этом случае он будет обрабатывать событие таймера, как только он завершит свою текущую задачу, или он в данный момент спит, и в этом случае он будет разбужен добавлением события. и обрабатывает его немедленно.
Хороший источник информации о том, как Apple , скорее всего, делает это (никто не может сказать наверняка, как, впрочем, и о его закрытом источнике), - это GNUStep. Так как GCC может обрабатывать Objective-C (это не просто расширение, которое поставляется только Apple, даже стандартный GCC может его обрабатывать), однако наличие Obj-C без всех основных классов, которые поставляет Apple, довольно бесполезно, сообщество GNU попыталось - реализуют наиболее распространенные классы Obj-C, которые вы используете на Mac, и их реализация - OpenSource.
Здесь вы можете загрузить недавний пакет с исходным кодом.
Распакуйте его и посмотрите детали реализации NSThread, NSObject и NSTimer. Я думаю, что Apple не делает это сильно по-другому, я мог бы доказать это с помощью GDB, но почему они сделали бы это по-другому, чем этот подход? Это умный подход, который работает очень хорошо:)