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

3
Delay is an easy-to-use micro-framework 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 9 10
## Installation

### Carthage

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

11 12 13 14 15
1. Add the framework to your Carfile. e.g.,

	```git "git@source.ind.ie:project/delay.git" ~> 1.0```

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

### Manual

#### iOS

21
This requires hacking the Xcode project file but it’s still the most elegant way of doing things. If you want a better way, [dupe this radar for seamless support of fat frameworks in Xcode](http://openradar.appspot.com/radar?id=4951631992979456).
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

1. Build the framework target.
2. In Xcode, add the framework to the Embed Binaries
3. Edit the `project.pbxproj` (in the <your-project>.xcodeproj folder) file and replace the line that reads something like:

	```A7E653511C2496F700988537 /* Delay.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Delay.framework; path = "../../path/in/DerivedData/to/Delay.framework"; sourceTree = "<group>"; };```

	With:

	```A7E653511C2496F700988537 /* Delay.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Delay.framework; path = "$(CONFIGURATION_BUILD_DIR)/Delay.framework"; sourceTree = "<group>"; };```

(In other words, you’re replacing the hardcoded path to the Delay.framework within your particular Derived Data folder with a generic one. This means that anyone else who checks out your project will get the correct framework.)

#### OS X

1. Just drag the framework into the Linked Frameworks and Binaries section of your project (under General).

(For an example of manually adding the framework, see the iOS and OS X demo apps that ship with this framework.)
Aral Balkan's avatar
Aral Balkan committed
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

## Usage

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

	delay(0.0)
	{
	  // Do something.
	}

### Execute after an arbitrary number of seconds

	delay(42.0)
	{
	  // Do something.
	}

### Cancel before execution

	let cancellableBlock = delay(42.0)
	{
	  // Do something.
	}

	cancellableBlock.cancel()

### Idiom: throttle user input

	var cancellableCommand:CancellableDelayedCommand?

	// …

	// 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:
        // …
    }

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

	var textDidChangeHandler:NotificationHandler?
	var cancellableAutoCompleteCommand:CancellableDelayedCommand?

	// …

	override func viewWillAppear()
	{
		textDidChangeHandler = handle(NSControlTextDidChangeNotification, from: myTextInput)
	    {
	        /* with */ notification in
98

Aral Balkan's avatar
Aral Balkan committed
99
	        let text = self.myTextInput.stringValue
100

Aral Balkan's avatar
Aral Balkan committed
101 102 103 104 105 106
	        // 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
	            // …
	        }
107
	    }
Aral Balkan's avatar
Aral Balkan committed
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
	}

	override func viewWillDisappear()
	{
		cancellableAutoCompleteCommand.cancel()
		textDidChangeHandler.remove()
	}

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

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.

## 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).)

126
Copyright © Aral Balkan.
Aral Balkan's avatar
Aral Balkan committed
127
Released with ♥ by [Ind.ie](https://ind.ie) under the MIT License.