Skip to content

theappbusiness/TABObserverSet

 
 

Repository files navigation

TABObserverSet - Kin + Carta Create

TABObserverSet

CI Status Version License Platform

TABObserverSet, originally conceived by Mike Ash, provides a Swift-y alternative to the traditional NotificationCenter style of reactive programming.

With a simple syntax, TABObserverSet is easy to use and read in your code.

Integration

Cocoapods

To integrate TABObserverSet using Cocoapods, simply add the following to your podfile:

pod 'TABObserverSet', '2.0.0' # Swift 4
pod 'TABObserverSet', '1.1.1' # Swift 3

Manual

If you're not using Cocoapods, you can integrate TABObserverSet into your project by adding ObserverSet.swift to your project's target.

Usage

Usage is very simple.

Similar to NotificationCenter, you have a single broadcaster and multiple observers. While NotificationCenter-style broadcasting can potentially result in a many-to-many relationship, TABObserverSet results in a one-to-many relationship, due to there only being a single broadcaster.

Here's a way you could set up a broadcaster:

class NetworkPoller {

  // Things that want to observe the broadcast can add themselves
  // to this `ObserverSet`
  let networkPollObservers = ObserverSet<Void>()

  // ... some magic code here which polls ... //

  private func networkPolled() {

    // Broadcast to any observers that the network has polled
    networkPollObservers.notify()
  }

}

Simple, right? In case you're wondering what the Void type is doing when setting up the observer set:

ObserverSet<Void>()

That's essentially declaring that we're not going to be passing in an argument when notifying observers.

You could declare that you will be passing any type, should you want to. Here's another example, where we pass an optional error when we notify observers:

class NetworkPoller {

  // Things that want to _subscribe_ to the _broadcast_ can add themselves
  // to this `ObserverSet`
  let networkPollObservers = ObserverSet<Error?>()

  // ... some magic code here which polls ... //

  private func networkPolled(_ error: Error?) {

    // Broadcast to any observers that the network has polled
    networkPollObservers.notify(error)
  }

}

So that's setting up the broadcaster, how about observers? That too is very simple:

let networkPoller = NetworkPoller()

class SettingsViewModel {

  init() {
    networkPoller.networkPollObservers.add(self, SettingsViewModel.networkPolled)
  }

  private func networkPolled(_ error: Error?) {
    if let error = error {
      print("Error! \(error)")
    } else {
      print("Network polled! :D")
    }
  }

}

class ResultsViewModel {

  init() {
    networkPoller.networkPollObservers.add(self, ResultsViewModel.networkPolled)
  }

  private func networkPolled(_ error: Error?) {
    if let error = error {
      print("Error! \(error)")
    } else {
      print("Network polled! :D")
    }
  }

}

In the above sample code, we have a single shared NetworkPoller instance (the broadcaster), and two view models which want to do their own thing when the network is polled, so they observe the event individually. This is not too disimillar from the way you can set up #selectors in Swift, but it's a lot cleaner.

You can also use closures to observe events, which is nice for testing:

func test_networkPoller_notifiesObservers() {
  let networkPoller = NetworkPoller()
  let expectation = self.expectation(description: "Wait for network to poll")
  networkPoller.networkPollObservers.add { error in
    XCTAssertNil(error)
    expectation.fulfill()
  }
  waitForExpectations(timeout: 1)
}

Credits

TABObserverSet is a fork of SwiftObserverSet, created by Mike Ash.

Credit should be given to Mike Ash for the original idea.

License

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

About

NotificationCenter re-conceptualization for Swift.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 92.2%
  • Ruby 6.0%
  • C 1.8%