An observables framework for Swift
Swift Ruby Objective-C
Clone or download
Latest commit 7b280dd Aug 7, 2018

🐌 snail Carthage compatible Cocoapods SwiftPM Compatible


A lightweight observables framework, also available in Kotlin



You can install Carthage with Homebrew using the following command:

brew update
brew install carthage

To integrate Snail into your Xcode project using Carthage, specify it in your Cartfile where "x.x.x" is the current release:

github "UrbanCompass/Snail" "x.x.x"

Swift Package Manager

To install using Swift Package Manager have your Swift package set up, and add Snail as a dependency to your Package.swift.

dependencies: [
    .Package(url: "", majorVersion: 0)


Add all the files from Snail/Snail to your project

Creating Observables

let observable = Observable<thing>()

Subscribing to Observables

    onNext: { thing in ... }, // do something with thing
    onError: { error in ... }, // do something with error
    onDone: { ... } //do something when it's done

Closures are optional too...

    onNext: { thing in ... } // do something with thing
    onError: { error in ... } // do something with error

Creating Observables Variables

let variable = Variable<whatever>(some initial value)
let optionalString = Variable<String?>(nil)
    onNext: { string in ... } // do something with value changes

optionalString.value = "something"
let int = Variable<Int>(12)
    onNext: { int in ... } // do something with value changes

int.value = 42

Miscellaneous Observables

let just = Just(1) // always returns the initial value (1 in this case)

enum TestError: Error {
  case test
let failure = Fail(TestError.test) //always fail with error

let n = 5
let replay = Replay(n) // replays the last N events when a new observer subscribes

Subscribing to Control Events

let control = UIControl()
  onNext: { ... }  // do something with thing

let button = UIButton()
  onNext: { ... }  // do something with thing


You can specify which queue an observables will be notified on by using .subscribe(queue: <desired queue>). If you don't specify, then the observable will be notified on the same queue that the observable published on.

There are 3 scenarios:

  1. You don't specify the queue. Your observer will be notified on the same thread as the observable published on.

  2. You specified main queue AND the observable published on the main queue. Your observer will be notified synchronously on the main queue.

  3. You specified a queue. Your observer will be notified async on the specified queue.


Subscribing on DispatchQueue.main

observable.subscribe(queue: .main,
    onNext: { thing in ... }

Weak self

To avoid retain cycles and/or crashes, always use [weak self] when self is needed by an observer

observable.subscribe(onNext: { [weak self] in
    // use self? as needed.

In Practice

Subscribing to Notifications

  .subscribe(queue: .main, onNext: { [weak self] notification in

Subscribing to Gestures

let panGestureRecognizer = UIPanGestureRecognizer()
  .subscribe(queue: .main, onNext: { [weak self] in

Subscribing to UIBarButton Taps

  .subscribe(onNext: { [weak self] in
    self?.dismiss(animated: true, completion: nil)