Skip to content

Commit

Permalink
Merge pull request #2 from luoxiu/1.x
Browse files Browse the repository at this point in the history
1.x
  • Loading branch information
luoxiu authored Aug 31, 2019
2 parents 16148d3 + 83f34b5 commit 226282d
Show file tree
Hide file tree
Showing 27 changed files with 659 additions and 889 deletions.
2 changes: 1 addition & 1 deletion .swift-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.2
5.0
10 changes: 0 additions & 10 deletions .swiftlint.yml

This file was deleted.

25 changes: 10 additions & 15 deletions Once.podspec
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
Pod::Spec.new do |s|
s.name = "Once"
s.version = "0.0.2"
s.summary = "Minimalists library to manage one-off operations."
s.description = <<-DESC
Once is a minimalists library to manage one-off operations.
DESC
s.homepage = "https://github.com/jianstm/Once"
s.version = "1.0.0"
s.summary = "Once allows you to manage the number of executions of a task using an intuitive API."
s.homepage = "https://github.com/luoxiu/Once"
s.license = { :type => "MIT", :file => "LICENSE" }
s.author = { "Quentin Jin" => "jianstm@gmail.com" }
s.source = { :git => "https://github.com/jianstm/Once.git", :tag => s.version.to_s }
s.author = { "Quentin Jin" => "luoxiustm@gmail.com" }
s.source = { :git => "https://github.com/luoxiu/Once.git", :tag => s.version.to_s }
s.source_files = "Sources/**/*"
s.frameworks = "Foundation"
s.requires_arc = true
s.swift_version = "4.2"
s.swift_version = "5.0"

s.ios.deployment_target = "8.0"
s.osx.deployment_target = "10.10"
s.watchos.deployment_target = "2.0"
s.tvos.deployment_target = "9.0"
s.ios.deployment_target = "10.0"
s.osx.deployment_target = "10.12"
s.watchos.deployment_target = "3.0"
s.tvos.deployment_target = "10.0"
end
178 changes: 44 additions & 134 deletions Once.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

177 changes: 94 additions & 83 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,88 +1,76 @@
# Once([简体中文](README.zh_cn.md))

<div align="center">

<a href="https://travis-ci.org/jianstm/Once">
<img src="https://travis-ci.org/jianstm/Once.svg?branch=master">
</a>
<a href="https://codecov.io/gh/jianstm/Once">
<img src="https://codecov.io/gh/jianstm/Once/branch/master/graph/badge.svg">
</a>
<img src="https://img.shields.io/badge/version-0.0.2-orange.svg">
<img src="https://img.shields.io/badge/support-CocoaPods%20%7C%20Carthage%20%7C%20SwiftPM-brightgreen.svg">
<img src="https://img.shields.io/badge/platform-iOS%20%7C%20macOS%20%7C%20watchOS%20%7C%20tvOS%20%7C%20Linux-lightgrey.svg">

<br>
<br>
<br>
<strong>Executes your task once and only once.</strong>
<p align="center">

[![Build Status](https://travis-ci.org/luoxiu/Once.svg?branch=master)](https://travis-ci.org/luoxiu/Once)
[![codecov](https://codecov.io/gh/luoxiu/Once/branch/master/graph/badge.svg)](https://codecov.io/gh/luoxiu/Once)
![release](https://img.shields.io/github/release-pre/luoxiu/Once)
![install](https://img.shields.io/badge/install-spm%20%7C%20cocoapods%20%7C%20carthage-ff69b4)
![platform](https://img.shields.io/badge/platform-ios%20%7C%20macos%20%7C%20watchos%20%7C%20tvos%20%7C%20linux-lightgrey)
![license](https://img.shields.io/github/license/luoxiu/combinex?color=black)

</div>

Once allows you to manage the number of executions of a task using an intuitive API.


## Highlight

- [x] Safe
- [x] Efficient
- [x] Persistent
- [x] Minimalist
- [x] Intuitive

## Usage

### Run
### Token

`Once.run` will execute your task once and only once during the lifetime of application, and no need to initialize a flag in advance~ 😉
`Token` records the number of times the task is executed in memory, which allows the task to be executed only once during the entire lifetime of the app.

You can think of it as an alternative to `dispatch_once` in OC:

```objectivec
static dispatch_once_t token;
dispatch_once(&token, ^{
// do something only once
});
```
The swift code using `Token` is as follows:
```swift
func doSomethingOnlyOnce() {
Once.run {
// No matter how many times `doSomethingOnlyOnce` is called,
// the message will only be printed once.
        // In multithreading, if the task is executing,
// the subsequent thread will wait for the execution ends.
print("Once!")
}
let token = Token.makeStatic()
token.do {
// do something only once
}
```

If you want to check if the same task has already been executed elsewhere, you can use `token`:
Or, more simple:

```swift
var i = 0
let token = Once.makeToken()

// a.swift
Once.run(token) {
i += 1
Token.do {
// do something only once
}
```

You can also don't use `static`:

// b.swift
Once.run(token) {
// No matter how many places it is called, the variable will only increment once.
i += 1
```swift
class Manager {
let loadToken = Token.make()

func ensureLoad() {
loadToken.do {
// do something only once per manager.
}
}
}
```

### Do

Unlike `run`, `do` will persist the execution history of the task (using `UserDefault`).

Before moving on to `do`, let's get to know a few simple concepts:

#### Period

`Period` represents a time period, its common usage is as follows:

```swift
let ago = Period.minute(30).ago // 30 minutes ago

let p0: Period = .year(1)
let p1: Period = .month(2)
let p2: Period = .day(3)

let p3 = p0 + p1 + p2
let later = p3.later
```
`PersistentToken` determines whether this task should be executed based on `Scope` and `TimesPredicate`.

#### Scope

Expand All @@ -93,64 +81,87 @@ let later = p3.later
- `.session`: from app launch
- `.since(let since)`: from `since(Date)`
- `.until(let until)`: to `until(Date)`
- `.every(let period)`: every `period(Period)`

Let's take a look at `do`:
#### TimesPredicate

`TimesPredicate` represents a range of times.

```swift
let showTutorial = Label(rawValue: "show tutorial")
let p0 = TimesPredicate.equalTo(1)
let p1 = TimesPredicate.lessThan(1)
let p2 = TimesPredicate.moreThan(1)
let p3 = TimesPredicate.lessThanOrEqualTo(1)
let p4 = TimesPredicate.moreThanOrEqualTo(1)
```

#### do

Once.do(showTutorial, scope: .version) { (sealer) in
You can use `Scope` and `TimesPredicate` to make any plan you want, and, yes, it is thread-safe.

```swift
let token = PersistentToken.make("showTutorial")
token.do(in: .version, if: .equalTo(0)) {
app.showTutorial()

// You always need to call `seal` to mark the task as done,
// otherwise the execution will not be logged.
// Same as `do`, in multithreading, if the task is executing,
// the subsequent thread will wait for the execution ends.
sealer.seal()
}

Once.if("remind", scope: .session, times: .lessThan(3)) { (sealer) in
app.remind()
sealer.seal()
// or
let later = 2.days.later
token.do(in: .until(later), if: .lessThan(5)) {
app.showTutorial()
}
```

#### done

Once.unless("pop ad", scope: .session, times: .equalTo(5)) { (sealer) in
app.popAd()
sealer.seal()
Sometimes your asynchronous task may fail. You don't want to mark the failed task as done. You can:

```swift
let token = PersistentToken.make("showAD")
token.do(in: .install, if: .equalTo(0)) { task in
networkService.fetchAD { result in
if result.isSuccess {
showAD(result)
task.done()
}
}
}
```

But at this time, the judgment is no longer absolutely safe - if there are multiple threads checking the token at the same time, but it should rarely happen, 😉.

#### reset

You can also clear the execution history of a task:

// Clear the history of the task.
Once.clear("pop ad")
```swift
token.reset()
```

It is also permissible to clear the execution history of all tasks, but at your own risk:

// Date of the last execution.
Once.lastDone(of: "pop ad")
```swift
PersistentToken.resetAll()
```

## Installation

### CocoaPods

```ruby
# Podfile
use_frameworks!

target 'YOUR_TARGET_NAME' do
pod 'Once', '~> 0.0.1'
end
pod 'Once', '~> 1.0.0'
```

### Carthage

```ruby
github "jianstm/Once" ~> 0.0.1
github "luoxiu/Once" ~> 1.0.0
```

### Swift Package Manager

```swift
dependencies: [
.package(url: "https://github.com/jianstm/Once", .upToNextMinor(from: "0.0.1"))
.package(url: "https://github.com/luoxiu/Once", .upToNextMinor(from: "1.0.0"))
]
```

Expand Down
Loading

0 comments on commit 226282d

Please sign in to comment.