GithubHelp home page GithubHelp logo

luoxiu / schedule Goto Github PK

View Code? Open in Web Editor NEW
1.8K 29.0 110.0 1008 KB

Schedule timing task in Swift using a fluent API. (A friendly alternative to Timer)

License: MIT License

Swift 99.29% Ruby 0.71%
timer human

schedule's Introduction

Schedule(简体中文)

Schedule is a timing tasks scheduler written in Swift. It allows you run timing tasks with elegant and intuitive syntax.

Features

  • Elegant and intuitive API
  • Rich preset rules
  • Powerful management mechanism
  • Detailed execution history
  • Thread safe
  • Complete documentation
  • ~100%+ test coverage

Why You Should Use Schedule

Features Timer DispatchSourceTimer Schedule
⏰ Interval-based Schedule
📆 Date-based Schedule
🌈 Combined Plan Schedule
🗣️ Natural Language Parse
🏷 Batch Task Management
📝 Execution Record
🎡 Plan Reset
🚦 Suspend, Resume, Cancel
🍰 Child-action

Usage

Overview

Scheduling a task has never been so elegant and intuitive, all you have to do is:

// 1. define your plan:
let plan = Plan.after(3.seconds)

// 2. do your task:
let task = plan.do {
    print("3 seconds passed!")
}

Rules

Interval-based Schedule

The running mechanism of Schedule is based on Plan, and Plan is actually a sequence of Interval.

Schedule makes Plan definitions more elegant and intuitive by extending Int and Double. Also, because Interval is a built-in type of Schedule, you don't have to worry about it being polluting your namespace.

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 { }

Date-based Schedule

Configuring date-based Plan is the same, with the expressive Swift syntax, Schedule makes your code look like a fluent conversation.

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 { }

Natural Language Parse

In addition, Schedule also supports simple natural language parsing.

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 { }

Combined Plan Schedule

Schedule provides several basic collection operators, which means you can use them to customize your own powerful plans.

/// 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)

Management

DispatchQueue

When calling plan.do to dispatch a timing task, you can use queue to specify which DispatchQueue the task will be dispatched to when the time is up. This operation does not rely on RunLoop like Timer, so you can call it on any thread.

Plan.every(1.second).do(queue: .global()) {
    print("On a globle queue")
}

RunLoop

If queue is not specified, Schedule will use RunLoop to dispatch the task, at which point the task will execute on the current thread. Please note, like Timer, which is also based on RunLoop, you need to ensure that the current thread has an available RunLoop. By default, the task will be added to .common mode, you can specify another mode when creating the task.

let task = Plan.every(1.second).do(mode: .default) {
    print("on default mode...")
}

Timeline

You can observe the execution record of the task in real time using the following properties.

task.creationDate

task.executionHistory

task.firstExecutionDate
task.lastExecutionDate

task.estimatedNextExecutionDate

TaskCenter & Tag

Tasks are automatically added to TaskCenter.default by default,you can organize them using tags and task center.

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

You can suspend, resume, cancel a task.

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()

Action

You can add more actions to a task and remove them at any time you want:

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)

Installation

CocoaPods

# Podfile
use_frameworks!

target 'YOUR_TARGET_NAME' do
  pod 'Schedule', '~> 2.0'
end

Carthage

github "luoxiu/Schedule" ~> 2.0

Swift Package Manager

dependencies: [
    .package(
      url: "https://github.com/luoxiu/Schedule", .upToNextMajor(from: "2.0.0")
    )
]

Contributing

Like Schedule? Thanks!!!

At the same time, I need your help~

Finding Bugs

Schedule is just getting started. If you could help the Schedule find or fix potential bugs, I would be grateful!

New Features

Have some awesome ideas? Feel free to open an issue or submit your pull request directly!

Documentation improvements.

Improvements to README and documentation are welcome at all times, whether typos or my lame English, 🤣.

Acknowledgement

Inspired by Dan Bader's schedule!

schedule's People

Contributors

apollozhu avatar austinpayne avatar brenthargrave avatar bryancaragay avatar ggabogarcia avatar hawflakes avatar krausefx avatar luoxiu avatar recherst avatar wilsongramer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

schedule's Issues

How to Plan for List of Dates

I was looking for List Dates Planning
we already have Plan.of(Date1, Date2), But i was looking for very Dynamic like Plan.of([Dates]).do{}

Mac没有响应

我作为按键事件来执行,没有任何响应
xcode 11.2
image

Plan.every(5.second).do is not working

Here is my simple code:

task = Plan.every(5.second).do {
    self.checkIfUnauthorized()
}
task?.resume()

This is only working one time.
I am running this code on iOS 12.2 with Xcode 10.2.1.

host:self 是否在v2.0已被移除

Plan.every(25.seconds).do(host: self) {
   print("Hello World")
}

请问是否能在v2的版本实现 只在当时的viewController执行任务?
谢谢🙏

mac开发

我用下面的方法进行操作时, 项目没有任何反应
image

daily task at a certain time...

first attempt:

let everyWeekdayTask = Plan.every([.sunday, .monday, .tuesday, .wednesday, .thursday, .friday, .saturday]).at("12 pm").do {}

result:

(lldb) po everyWeekdayTask.estimatedNextExecutionDate
nil

second attempt:

        let sunPlan = Plan.every(.sunday).at("12 pm")
        let monPlan = Plan.every(.monday).at("12 pm")
        let tuePlan = Plan.every(.tuesday).at("12 pm")
        let wedPlan = Plan.every(.wednesday).at("12 pm")
        let thuPlan = Plan.every(.thursday).at("12 pm")
        let friPlan = Plan.every(.friday).at("12 pm")
        let satPlan = Plan.every(.saturday).at("12 pm")
        let everyWeekdayTask2 = sunPlan.concat(monPlan).concat(tuePlan).concat(wedPlan).concat(thuPlan).concat(friPlan).concat(satPlan).do {}

result:

(lldb) po everyWeekdayTask2.estimatedNextExecutionDate
▿ Optional<Date>
  ▿ some : 2019-10-20 09:00:00 +0000
    - timeIntervalSinceReferenceDate : 593254800.000214

It seems to be working, but we lost one day. Today is Friday the 18th, and the nearest next timer operation is set to Sunday the 20th (do not look at the time, it is adjusted according to the timezone). That is, we lost somewhere Saturday.

Can you tell me how to correctly make a task for each day at a certain time?

Can't running


import SwiftUI
import Schedule

struct TestView: View {
	
		var body: some View {
		HStack {
			
			
			Button(action:{
				
			
				let plan = Plan.after(3.seconds)
				let task = plan.do {
					print("test 3")
				}
				print("created task")
				//task.executeNow()
			}){
				
				Text("test")
			}

	}
}



Hello, I am developing an app with SWIFTUI, but I don't know how to invoke the schedule. it output nothing for me. needs any setup for it?

Carthage - Task failed with exit code 65

Current release could not be build succeed via Carthage
*** Fetching Schedule *** Checking out Schedule at "1.0.0" *** xcodebuild output can be found in /var/folders/v0/wqvywl4s5hxdxb1fn1w4nc7w0000gn/T/carthage-xcodebuild.29bWFa.log *** Building scheme "Schedule-iOS" in Schedule.xcodeproj Build Failed Task failed with exit code 65: /usr/bin/xcrun xcodebuild -project /Users/hai/lab/cart/Carthage/Checkouts/Schedule/Schedule.xcodeproj -scheme Schedule-iOS -configuration Release -derivedDataPath /Users/hai/Library/Caches/org.carthage.CarthageKit/DerivedData/9.4.1_9F2000/Schedule/1.0.0 -sdk iphoneos ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES archive -archivePath /var/folders/v0/wqvywl4s5hxdxb1fn1w4nc7w0000gn/T/Schedule SKIP_INSTALL=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=NO CLANG_ENABLE_CODE_COVERAGE=NO STRIP_INSTALLED_PRODUCT=NO (launched in /Users/hai/lab/cart/Carthage/Checkouts/Schedule)

Proposal new logo to SCHEDULE

Hello sir, I'm a graphic designer, I'm interested in open source projects. I would like to design a logo for your Project. I will be happy to collaborate with you :)

Does it still support iOS 10 ?

Hi @jianstm ,
I have built Schedule via Carthage (Xcode 9.4.1) then integrate to a project and they said:
Module file's minimum deployment target is ios11.4 v11.4: /Users/hai/Frameworks/Schedule.framework/Modules/Schedule.swiftmodule/x86_64.swiftmodule

I have checked Schedule's targets they are setting from 10.10, could you investigate this ?

APP切换到后台,不能继续执行任务

如果是APP退出到后台,这个 task,不能再继续执行,是不是需要使用者自行管理?
如果 Schedule 目前没有这个功能,建议添加切换到后台仍旧可以继续执行任务

resume 有时候无效

场景:
executeNow()
resume()

有时候是正常的,有时候只会执行一次任务, 显然是 executeNow执行的任务,

出现概率 百分 50左右。
定时器的时间为 : 3秒

estimatedNextExecution is nill

let plan = Plan.every(.tuesday, .sunday).at("12:00").do { print("Happy holiday") } print(plan.timeline.estimatedNextExecution) //nill

When today is Tuesday, it seems that the schedule containing Tuesday is not registered.
I wonder if it was intended?

Background Run

It's supports to run in background? I don't found it on documentation.

代码不执行

直接使用示例代码,在pod文件中断点直接跳出。
版本:2.0.2
屏幕快照 2019-07-10 下午6 52 58

同事用手动拖入的方法也不执行

截图我是一个demo,也不执行

还维护吗

这个库目前还维护吗,考虑到一些后续情况...

指定week or month 无法do it

Plan.every(.wednesday).at(14, 40).do() {}
使用swift4.0 xcode10.1
此方法 会造成内存泄露,并且没有执行do中的内容。真机和模拟器都会发生

Can't get demo 3 second task to run

I have this service I would like to run from my root viewcontroller in ios in viewDidLoad.

    /** every period we process this plan */
    static func periodicallyProcessPlanTask () {
        print("scheduling periodic plan processing")
        
        TaskCenter.default.cancel(byTag: "notificationsDispatch")
        
        print ("still processing")
        let queue = DispatchQueue(label: "notificationsDispatch", qos: .default)

        let newPlan = Plan.after(3.seconds)
        let newTask = newPlan.do(queue: queue) {
            print("periodically processing background notifications")
            PreferencesModel.shared.processBackgroundNotificationsQueue()
        }

        print ("scheduled processing!!")
        TaskCenter.default.addTags(["notificationsDispatch"], to: newTask)
    }

note that the print statements are in there to debug. I do call this, which exists in its own PlanService class, from viewdidload:

class RootViewController: UIViewController {
//...    
    var loadCount = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        
        if loadCount == 0 {
            PlanService.periodicallyProcessPlanTask()
        }
        loadCount += 1

and I do see print statements to verify that it did load, but not the one that records it executing:

scheduling periodic plan processing
still processing
scheduled processing!!

even if I comment out the other line in the task, leaving nothing but a print statement, it does not execute. Also, if I move the task to AppDelegate's didFinishLaunchingWithOptions, it does not run.

If I add "newTask.executeNow()" it does run. but that kinda defeats the purpose (I'd like this to run either every 15 minutes or perhaps every hour). Also, in the debugger I can see that it does have an estimatedNextExecutionDate which seems correct.

Where do I have to be to be able to run the function? Do I have to first background the app ni order for it too run or something?

Thanks!

Just wanted to say thank you for wishing me a happy birthday in your code example! I knew the world revolved around me, but its always nice to see proof! 🥇

Haha - very nicely designed lib/api though! Do appreciate.

Task every day not work?

I am confused how it work?
Assume that now is Friday 15:10:00

let task = Plan.every(.friday).at(15,11).do { print("Execute task") }

But nothing printed at 15:11
Is there something wrong here?
(I tested in playground)

Task is getting deallocated.

I am using the task as shown below and used as a property to singleton class.

            schedulerTask = Plan.every(0.5).do(queue: .global()) {
doSomething()
            }

Which is resulting in this crash.
Screenshot 2019-06-04 at 10 47 46 AM

struct `Plan` api errors

let t3 = Plan.every(.firday).at("9:00 pm").do { }

error: Reference to member 'firday' cannot be resolved without a contextual type

let t4 = Plan.every("tuesday").at("9:00 pm").do { }

error: Static member 'at' cannot be used on instance of type 'Plan'

the first option from the documentation...
using: Xcode 11.1, swift 5

Cancel a repeating task

I'm having trouble understanding how to manage tasks. Task provides methods like cancel, which is really important if, for example, you want to stop a repeating task.

A clear use case is for repeating tasks. Before scheduling a repeating task, you probably want to make sure one is not already running. To do that, you would likely want to do something like:

if let oldTask = UserPreferencesService.getPlannedTask() {
  oldTask.cancel()
}
let newTask = Plan.at(date, repeating: when).do { something() }
UserPreferencesService.savePlannedTask(newTask)

however, this is problematic. How do you encode the task so you can save it and restore the pointer to go find it again later?

修改Task的执行时间

你好,有个问题请教一下,这里有个两秒后执行的task,假设当前时间是t0
let somePlan = Plan.after(2.second)
let after2Task = somePlan.do(onElapse: {
//Do something
})
在after2Task即将开始执行前,假如是t0后1.9s,我调用了如下方法
after2Task.setLifetime(2.second) 录得after2Task实际执行的时间t1
预想t1-t0 = 3.9,但实际t1-t0 = 2。请问类似的效果应该如何实现

Memory Leak

I noticed this library is leaking RunLoopTask:

image

and can be reproduced with this trivial macOS example:

class ViewController: NSViewController {
    var task: Task?
    @IBAction func onButtonPress(_ sender: Any) {
        task = Plan.after(Interval(seconds: 2)).do {
            print("Hi")
        }
    }
}

Cocoapods error

Installing Schedule (0.0.4)
....
warning: Could not find remote branch 0.0.4 to clone.
fatal: Remote branch 0.0.4 not found in upstream origin

Suspension problem

I have a task:

let task = Plan.every(5.seconds).do(action: startSome)

When I suspend() it somewhere and then resume for 10 seconds, I have 2 immediate calls of startSome.
But what I want is call startSome in (5sec - time remaining when I called suspend).
Is it possible?

'TaskCenter' initializer is inaccessible due to 'internal' protection level

when I try to initialize TaskCenter:

let taskCeneter = TaskCenter()

I get this error:
'TaskCenter' initializer is inaccessible due to 'internal' protection level

As long as you do not implement init() explicitly, it is marked as internal by default. You need to overwrite that permission level to be able to instantiate from outside your framework.

Or is there some special reason why you don't want to make it available ?

Ubuntu 18.04 build not working, Mac works fine

Hi I am having an issue with this library. It worked flawlessly on my Macbook. When I deployed to Ubuntu 18.04 (my AWS server) and tried to build the project I get the following errors:

image

Any ideas?

Thank you

Schedule make the ipa file cannot be run on iOS

I used Schedule in my project then export ipa file succeed also installed on my device.
Unfortunately, this app cannot be launch, the ios said "Unable to install "My App",

So I temporary remove Schedule then the app can launch now.

Ubuntu 16.04 package build has some errors, Mac is fine

Environment:

System:Ubuntu 16.04

Swfit version:Swift version 4.2-dev (LLVM da1c9a3ae4, Clang 78aa734eee, Swift 68f32fc2aa)
Target: x86_64-unknown-linux-gnu

Swift package tools version:3.1.0

import PackageDescription

let package = Package(
    name: "Test",
    targets: [],
    dependencies: [
        .Package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", majorVersion: 3),
        .Package(url: "https://github.com/jianstm/Schedule.git", majorVersion: 0),
        ]
)

Swift build error
image

Is it still working ?

The code

let planWorkTimer = Plan.every(.monday, .tuesday, .wednesday, .thursday, .friday).at("6:49 am").do {
            print("planWorkTimer is start")
}

not print.

Swift Package Manager Install Fails - 2.0.0

Trying to install using Swift Package Manager results in dependency error.

Using Package File

let package = Package(
    name: "DMXTest",
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        .package(
            url: "https://github.com/yeokm1/SwiftSerial.git", .upToNextMajor(from:"0.0.0")
        ),
        .package(
            url: "https://github.com/jianstm/Schedule", .upToNextMajor(from: "2.0.0")
        ),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
        .target(
            name: "DMXTest",
            dependencies: ["SwiftSerial", "Schedule"]),
        .testTarget(
            name: "DMXTestTests",
            dependencies: ["DMXTest", "SwiftSerial"]),
    ]
)

Fails with:

Updating https://github.com/jianstm/Schedule
Updating https://github.com/yeokm1/SwiftSerial.git
error: dependency graph is unresolvable; found these conflicting requirements:

Dependencies:
    https://github.com/jianstm/Schedule @ 2.0.0..<3.0.0

Changing Schedule from 2.0.0 dependency to 1.0.0 dependency does install without errors. It appears to be just the 2.0.0 release.

Hope this helps!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.