readme.md 3.48 KB
Newer Older
Aral Balkan's avatar
Aral Balkan committed
1 2
# Delay

3
Delay is an easy-to-use micro-library for delaying code execution in a cancellable manner. It uses Grand Central Dispatch and blocks.
Aral Balkan's avatar
Aral Balkan committed
4

5 6 7 8
## Installation

[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)

Aral Balkan's avatar
Aral Balkan committed
9
### 1. Update your Cartfile
Aral Balkan's avatar
Aral Balkan committed
10 11

**Swift 3 (latest version)**
Aral Balkan's avatar
Aral Balkan committed
12 13

```
Aral Balkan's avatar
Aral Balkan committed
14
git "git@source.ind.ie:project/delay.git" ~> 3.0
Aral Balkan's avatar
Aral Balkan committed
15 16
```

Aral Balkan's avatar
Aral Balkan committed
17
For Swift 2.3, use the swift-2.3 branch:
18

Aral Balkan's avatar
Aral Balkan committed
19 20 21
```
git "git@source.ind.ie:project/delay.git" "swift-2.3"
```
22

Aral Balkan's avatar
Aral Balkan committed
23
To stay on Swift 2.2, use the 2.0.3 tag:
24 25

```
Aral Balkan's avatar
Aral Balkan committed
26
git "git@source.ind.ie:project/handle.git" ~> 2.0.3
27 28
```

Aral Balkan's avatar
Aral Balkan committed
29
### 2. Add the framework to your Xcode project
Aral Balkan's avatar
Aral Balkan committed
30 31 32 33

[Follow the instructions on Carthage’s readme](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application).

## Demos
34

Aral Balkan's avatar
Aral Balkan committed
35 36
1. Run the `./install` script to install the dependencies for the demo apps.
2. Run the `./dev` script and play with the iOS and macOS demo apps.
Aral Balkan's avatar
Aral Balkan committed
37

38
## Usage
Aral Balkan's avatar
Aral Balkan committed
39 40 41 42 43 44 45 46 47

Delay has three main use cases:

  * Delay execution of a block to the next stack frame (next frame of the runloop)
  * Delay execution by N seconds
  * Delay execution in a cancellable manner

### Execute on next stack frame

48
```swift
Aral Balkan's avatar
Aral Balkan committed
49
_ = delay(0.0)
50 51 52 53
{
  // Do something.
}
```
Aral Balkan's avatar
Aral Balkan committed
54 55 56

### Execute after an arbitrary number of seconds

57
```swift
Aral Balkan's avatar
Aral Balkan committed
58
_ = delay(42.0)
59 60 61 62
{
  // Do something.
}
```
Aral Balkan's avatar
Aral Balkan committed
63 64
### Cancel before execution

65 66 67 68 69 70 71
```swift
let cancellableBlock = delay(42.0)
{
  // Do something.
}
cancellableBlock.cancel()
```
Aral Balkan's avatar
Aral Balkan committed
72 73 74

### Idiom: throttle user input

75 76
```swift
var cancellableCommand:CancellableDelayedCommand?
Aral Balkan's avatar
Aral Balkan committed
77

78
// …
Aral Balkan's avatar
Aral Balkan committed
79

80 81 82 83 84 85 86 87
// Throttle expensive operation so it is performed at
// most every second, no matter how often a signal is received.
cancellableCommand = cancellableCommand?.reset() ?? delay(1.0)
{
  // Perform expensive operation:
  // …
}
```
Aral Balkan's avatar
Aral Balkan committed
88 89 90

For example, you can use this to implement auto-complete without flooding the lookup method on every keystroke.

91 92 93
```swift
var textDidChangeHandler:NotificationHandler?
var cancellableAutoCompleteCommand:CancellableDelayedCommand?
Aral Balkan's avatar
Aral Balkan committed
94

95
// …
Aral Balkan's avatar
Aral Balkan committed
96

97 98
override func viewWillAppear()
{
Aral Balkan's avatar
Aral Balkan committed
99
  textDidChangeHandler = handle(NSControlTextDidChangeNotification, from: myTextInput)
100 101
  {
    /* with */ notification in
102

103
    let text = self.myTextInput.stringValue
104

105 106 107 108 109 110 111 112
    // Throttle auto-complete lookups to every 1/3rd of a second.
    cancellableAutoCompleteCommand = cancellableAutoCompleteCommand?.reset() ?? delay(0.3)
    {
      // Perform expensive operation: look-up text for auto-complete
      // …
    }
  }
}
Aral Balkan's avatar
Aral Balkan committed
113

114 115 116 117 118 119
override func viewWillDisappear()
{
  cancellableAutoCompleteCommand.cancel()
  textDidChangeHandler.remove()
}
```
Aral Balkan's avatar
Aral Balkan committed
120 121 122 123 124

Read more about the library [in this blog post](https://ind.ie/labs/blog/delay) on [Ind.ie Labs](https://ind.ie/labs).

## On performance

Aral Balkan's avatar
Aral Balkan committed
125
Note that Delay is optimised for ease of authoring, beauty of interface, and clarity of intent. I haven’t run into performance issues and hence haven’t felt the need to run any benchmarks at the moment but [Evgenii Rtishchev’s purely-block-based CancelBlocks](https://github.com/katleta3000/CancelBlocks/blob/master/CancelBlocks.swift), on which my solution is based, is a lighter alternative should you need it.
Aral Balkan's avatar
Aral Balkan committed
126 127 128 129 130

## Credits

Delay based on the work of [Evgenii Rtishchev](https://github.com/katleta3000/CancelBlocks) and [Chris Brind](http://stackoverflow.com/questions/24034544/dispatch-after-gcd-in-swift/24318861#24318861) (with thanks to [Cezary Wojcik](http://stackoverflow.com/a/24034838/253485).)

131
Copyright © Aral Balkan.
132
Released with ♥ by [Ind.ie](https://ind.ie) under the MIT License.