Schedule 是一个用 Swift 编写的定时任务调度器。它允许你使用优雅且直观的语法运行定时任务。
特性 | Timer | DispatchSourceTimer | Schedule |
---|---|---|---|
⏰ 基于间隔的 Schedule | ✓ | ✓ | ✓ |
📆 基于日期的 Schedule | ✓ | ✓ | |
🌈 组合计划 Schedule | ✓ | ||
🗣️ 自然语言解析 | ✓ | ||
🏷 批量任务管理 | ✓ | ||
📝 执行记录 | ✓ | ||
🎡 计划重置 | ✓ | ✓ | |
🚦 暂停、恢复、取消 | ✓ | ✓ | |
🍰 子操作 | ✓ |
调度一个任务从未如此优雅和直观,你所需要做的就是
// 1. define your plan:
let plan = Plan.after(3.seconds)
// 2. do your task:
let task = plan.do {
print("3 seconds passed!")
}
Schedule 的运行机制基于 Plan
,而 Plan
实际上是一个 Interval
序列。
Schedule 通过扩展 Int
和 Double
,使 Plan
的定义更加优雅和直观。此外,由于 Interval
是 Schedule 的内置类型,你无需担心它会污染你的命名空间。
let t1 = Plan.every(1.second).do { }
let t2 = Plan.after(1.hour, repeating: 1.minute).do { }
let t3 = Plan.of(1.second, 2.minutes, 3.hours).do { }
配置基于日期的 Plan
也是一样的,凭借富有表现力的 Swift 语法,Schedule 使你的代码看起来像流畅的对话。
let t1 = Plan.at(date).do { }
let t2 = Plan.every(.monday, .tuesday).at("9:00:00").do { }
let t3 = Plan.every(.september(30)).at(10, 30).do { }
let t4 = Plan.every("one month and ten days").do { }
let t5 = Plan.of(date0, date1, date2).do { }
此外,Schedule 还支持简单的自然语言解析。
let t1 = Plan.every("one hour and ten minutes").do { }
let t2 = Plan.every("1 hour, 5 minutes and 10 seconds").do { }
let t3 = Plan.every(.friday).at("9:00 pm").do { }
Period.registerQuantifier("many", for: 100 * 1000)
let t4 = Plan.every("many days").do { }
Schedule 提供了几个基本的集合运算符,这意味着你可以使用它们来定制你自己的强大计划。
/// Concat
let p0 = Plan.at(birthdate)
let p1 = Plan.every(1.year)
let birthday = p0.concat.p1
let t1 = birthday.do {
print("Happy birthday")
}
/// Merge
let p3 = Plan.every(.january(1)).at("8:00")
let p4 = Plan.every(.october(1)).at("9:00 AM")
let holiday = p3.merge(p4)
let t2 = holiday.do {
print("Happy holiday")
}
/// First
let p5 = Plan.after(5.seconds).concat(Schedule.every(1.day))
let p6 = s5.first(10)
/// Until
let p7 = P.every(.monday).at(11, 12)
let p8 = p7.until(date)
当调用 plan.do
来调度一个定时任务时,你可以使用 queue
来指定任务在时间到达时将被调度到哪个 DispatchQueue
。此操作不依赖于像 Timer
那样的 RunLoop
,因此你可以在任何线程上调用它。
Plan.every(1.second).do(queue: .global()) {
print("On a globle queue")
}
如果未指定 queue
,Schedule 将使用 RunLoop
来调度任务,此时任务将在当前线程上执行。请注意,与同样基于 RunLoop
的 Timer
一样,你需要确保当前线程具有可用的 RunLoop
。默认情况下,任务将被添加到 .common
模式,你可以在创建任务时指定其他模式。
let task = Plan.every(1.second).do(mode: .default) {
print("on default mode...")
}
你可以使用以下属性实时观察任务的执行记录。
task.creationDate
task.executionHistory
task.firstExecutionDate
task.lastExecutionDate
task.estimatedNextExecutionDate
任务默认会自动添加到 TaskCenter.default
,你可以使用标签和任务中心来组织它们。
let plan = Plan.every(1.day)
let task0 = plan.do(queue: myTaskQueue) { }
let task1 = plan.do(queue: myTaskQueue) { }
TaskCenter.default.addTags(["database", "log"], to: task1)
TaskCenter.default.removeTag("log", from: task1)
TaskCenter.default.suspend(byTag: "log")
TaskCenter.default.resume(byTag: "log")
TaskCenter.default.cancel(byTag: "log")
TaskCenter.default.clear()
let myCenter = TaskCenter()
myCenter.add(task0)
你可以 suspend
、resume
、cancel
一个任务。
let task = Plan.every(1.minute).do { }
// will increase task's suspensionCount
task.suspend()
// will decrease task's suspensionCount,
// but don't worry about excessive resumptions, I will handle these for you~
task.resume()
// will clear task's suspensionCount
// a canceled task can't do anything, event if it is set to a new plan.
task.cancel()
你可以向任务添加更多操作,并在任何你想要的时候移除它们
let dailyTask = Plan.every(1.day)
dailyTask.addAction {
print("open eyes")
}
dailyTask.addAction {
print("get up")
}
let key = dailyTask.addAction {
print("take a shower")
}
dailyTask.removeAction(byKey: key)
# Podfile
use_frameworks!
target 'YOUR_TARGET_NAME' do
pod 'Schedule', '~> 2.0'
end
github "luoxiu/Schedule" ~> 2.0
dependencies: [
.package(
url: "https://github.com/luoxiu/Schedule", .upToNextMajor(from: "2.0.0")
)
]
喜欢 Schedule 吗? 谢谢!!!
同时,我需要你的帮助~
Schedule 刚刚起步。如果你能帮助 Schedule 发现或修复潜在的 Bug,我将不胜感激!
有一些很棒的想法?随时提出 issue 或直接提交你的 pull request!
随时欢迎改进 README 和文档,无论是错别字还是我蹩脚的英语,🤣。
灵感来自 Dan Bader 的 schedule!