Latest 0.4.0
License MIT
Platforms ios 8.0, requires ARC
Frameworks Foundation

Write synchronous, testable core easily with Chop.

CI Status

What is Chop?

Chop is a Swift microframework providing implementations of tasks and task groups.

  • Tasks are abstractions over asynchronous processes that can yield several values during their lifetime (think of progressive images or cached-then-remote values). They can also finish with an error. Tasks are lazy – which means they are not started before they really need to. Furthermore, tasks are cancelled when they are no longer referenced (i.e. deallocated), freeing up resources they are associated with.
  • Task Groups are execution contexts for tasks. They allow to place uniqueness constraints on tasks and apply a variety of behaviors around that. Task Groups also free up all tasks they manage when they are deallocated, making them a nice way to tie particular tasks to, say, user interface.

Here is a small example of how Chop can be used to execute a task that progressively loads a collection of items (for example, first fetching the locally cached value, and then the remote value). Only one task is allowed to execute; subsequent similar tasks are ignored until the first one finishes:

// The context in which the tasks can execute. 
// `policy` describes what should be done if a task with an identical `taskId` is added to group.
// In this case we want to ignore subsequent tasks with the same `taskId` until the first is completed.
// Other options exist.
let taskGroup = TaskGroup(policy: .ignore)

self.isLoading = true
  .fetchIssues(request, itemLimit: 10, progressive: true) // API that exposes a Chop'esque interface.
  .onUpdate { [weak self] in
    // Can be executed multiple times (i.e. providing first cached items, then remote items).
    self?.items = $0
  .onFailure { [weak self] in
    // Executed only once if error occurs.
  .onCompletion { [weak self] in
    // Executed when the task has finished, regardless of result.
    self?.isLoading = false 
  // `taskId` is optional - it will be 
  .registerIn(self.taskGroup, taskId: "itemFetch")

The task is created like this:

func fetchIssues(request: IssueRequest, itemLimit: UInt, progressive: Bool) -> Task<[Issue]> {
  return Task {
    let localItems = self.localDB.getItems(request)
    // Send local items through to the Task subscribers.

    // The following operation is asynchronous.
    var urlSessionTask = self.httpClient.getItems(request) { result in
      switch result {
        // Once again send data through to the Task subscribers.
        case .success(let issues): $0(.update(issues))
        // Or, otherwise, send error.
        case .failure(let error):  $0(.error(localResponse))

    // In this closure we perform cleanup. It will be called if the task is finished or cancelled.
    return { urlSessionTask.cancel(); urlSessionTask = nil }

The task performs work only as long as it is referenced by a TaskGroup. Consequently, if the TaskGroup is destroyed, all managed tasks are interrupted and you don’t have to care about them anymore.


Chop requires Swift 3.2. Swift 4 is supported as well.


Chop is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod "Chop"


Ivan Moskalev, [email protected]


Chop is available under the MIT license. See the LICENSE file for more info.

Latest podspec

    "name": "Chop",
    "version": "0.4.0",
    "summary": "Future / PackagedTask on steroids. Typesafe abstraction over lazy, composable async operations.",
    "description": "Chop is a delightful framework that provides a simple and expressive way to manage async operations.",
    "homepage": "",
    "license": "MIT",
    "authors": {
        "Ivan Moskalev": "[email protected]"
    "source": {
        "git": "",
        "tag": "0.4.0"
    "social_media_url": "",
    "platforms": {
        "ios": "8.0"
    "requires_arc": true,
    "source_files": "lib/*.swift",
    "frameworks": "Foundation",
    "pushed_with_swift_version": "4.0"

Pin It on Pinterest

Share This