Ответ
Да, можно создать собственный Run Loop с помощью низкоуровневого API Core Foundation — CFRunLoopCreate(). Однако в подавляющем большинстве сценариев используется существующий Run Loop текущего потока (RunLoop.current).
Создание нового Run Loop (редкий случай):
import Foundation
// Создание нового CFRunLoopRef
let customRunLoop = CFRunLoopCreate()
// Добавление источника событий (например, таймера или порта)
let source = ... // CFRunLoopSourceRef
CFRunLoopAddSource(customRunLoop, source, CFRunLoopMode.defaultMode)
// Запуск Run Loop (блокирует текущий поток!)
CFRunLoopRun()
Работа с Run Loop текущего потока (типичный use case):
// Получение Run Loop текущего потока
let currentRunLoop = RunLoop.current
// Добавление источника (например, таймера)
let timer = Timer(timeInterval: 1.0, repeats: true) { _ in
print("Tick")
}
currentRunLoop.add(timer, forMode: .default)
// Запуск Run Loop (блокирует поток до остановки)
currentRunLoop.run()
// ИЛИ управляемый запуск на время:
currentRunLoop.run(until: Date().addingTimeInterval(5.0))
Важные замечания:
- Источники: Run Loop немедленно завершится, если в нем нет хотя бы одного источника (timer, port, source).
- Главный поток: Главный поток приложения уже имеет работающий Run Loop, управляемый
UIApplication. - Фоновые потоки: Создание/запуск Run Loop актуально для вторичных потоков, которым необходимо обрабатывать асинхронные события (например, сетевые сокеты в старом стиле).
- Блокировка: Метод
run()блокирует поток. Для фоновых задач предпочтительнее использоватьrun(mode:before:)илиrun(until:)в цикле для более контролируемого выполнения.