Планировщик задач на Swift для iOS и macOS: полное руководство
В современной разработке под iOS и macOS планировщик задач (task scheduler) — это ключевой компонент для создания эффективных и отзывчивых приложений. Swift предоставляет несколько мощных инструментов для реализации планирования: от простых таймеров до интеграции с системным календарём через EventKit и низкоуровневых механизмов DispatchSource. В этой статье мы подробно разберём, как создать надёжный планировщик задач на Swift для обеих платформ.
Основные компоненты планировщика задач Swift
Прежде чем писать код, важно понять, какие инструменты доступны разработчику Swift:
- Timer — базовый класс для выполнения кода через заданные интервалы или с задержкой.
- DispatchSourceTimer — более производительный таймер на основе Grand Central Dispatch (GCD).
- EventKit — фреймворк для работы с календарём и напоминаниями на iOS/macOS.
- UNUserNotificationCenter — система локальных уведомлений для отложенного оповещения пользователя.
- Background Tasks — для выполнения фоновых задач на iOS 13+.
Базовый таймер с использованием Timer
Самый простой способ создать планировщик задач — использовать Timer. Однако помните, что он работает в основном потоке, если не указать обратное.
import Foundation
class SimpleTaskScheduler {
var timer: Timer?
func scheduleTask(interval: TimeInterval, repeats: Bool, task: @escaping () -> Void) {
timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: repeats) { _ in
task()
}
}
func cancel() {
timer?.invalidate()
timer = nil
}
}
// Пример использования
let scheduler = SimpleTaskScheduler()
scheduler.scheduleTask(interval: 5.0, repeats: true) {
print("Задача выполнена через 5 секунд")
}
Продвинутый планировщик с DispatchSourceTimer
Для более точного и производительного планирования используйте DispatchSourceTimer. Он работает в фоновых очередях и не блокирует UI.
import Foundation
class AdvancedTaskScheduler {
private var timer: DispatchSourceTimer?
private let queue = DispatchQueue(label: "com.pythonlib.scheduler", qos: .background)
func scheduleTask(deadline: DispatchTime, interval: DispatchTimeInterval? = nil, leeway: DispatchTimeInterval = .seconds(1), task: @escaping () -> Void) {
timer?.cancel()
timer = DispatchSource.makeTimerSource(queue: queue)
if let interval = interval {
timer?.schedule(deadline: deadline, repeating: interval, leeway: leeway)
} else {
timer?.schedule(deadline: deadline, leeway: leeway)
}
timer?.setEventHandler { [weak self] in
guard self?.timer != nil else { return }
task()
}
timer?.activate()
}
func cancel() {
timer?.cancel()
timer = nil
}
}
// Использование
let advancedScheduler = AdvancedTaskScheduler()
advancedScheduler.scheduleTask(deadline: .now() + 2.0, interval: .seconds(10)) {
print("Фоновая задача выполняется каждые 10 секунд")
}
Интеграция с EventKit для календарных задач
EventKit позволяет создавать задачи, которые синхронизируются с системным календарём. Это идеально для приложений-планировщиков.
import EventKit
class CalendarTaskScheduler {
let eventStore = EKEventStore()
func requestAccess(completion: @escaping (Bool) -> Void) {
eventStore.requestAccess(to: .event) { granted, error in
completion(granted)
}
}
func createScheduledTask(title: String, startDate: Date, endDate: Date, notes: String? = nil) -> EKEvent? {
let event = EKEvent(eventStore: eventStore)
event.title = title
event.startDate = startDate
event.endDate = endDate
event.notes = notes
event.calendar = eventStore.defaultCalendarForNewEvents
do {
try eventStore.save(event, span: .thisEvent)
return event
} catch {
print("Ошибка сохранения задачи: \(error.localizedDescription)")
return nil
}
}
func fetchTasks(from startDate: Date, to endDate: Date) -> [EKEvent] {
let predicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: nil)
return eventStore.events(matching: predicate)
}
}
// Пример
let calendarScheduler = CalendarTaskScheduler()
calendarScheduler.requestAccess { granted in
if granted {
let task = calendarScheduler.createScheduledTask(
title: "Встреча с командой",
startDate: Date().addingTimeInterval(3600),
endDate: Date().addingTimeInterval(7200),
notes: "Обсуждение спринта"
)
print("Задача создана: \(task?.title ?? "Ошибка Также в библиотеке
Авторизация и аутентификация в Go (Golang): полное руководство
Работа с изображениями в C# (.NET): библиотеки, инструменты и примеры
OAuth клиент для Go (Golang): полное руководство по библиотеке
Email отправка на JavaScript (Node.js) — библиотеки и примеры кода
tsyringe для TypeScript: полное руководство с примерами