Issue #96

Another cool thing about ios-oss is how it manages dependencies. Usually you have a lot of dependencies, and it’s good to keep them in one place, and inject it to the objects that need.

The Environment is simply a struct that holds all dependencies throughout the app

 A collection of **all** global variables and singletons that the app wants access to.
public struct Environment {
  /// A type that exposes endpoints for fetching Kickstarter data.
  public let apiService: ServiceType

  /// The amount of time to delay API requests by. Used primarily for testing. Default value is `0.0`.
  public let apiDelayInterval: DispatchTimeInterval

  /// A type that exposes how to extract a still image from an AVAsset.
  public let assetImageGeneratorType: AssetImageGeneratorType.Type

  /// A type that stores a cached dictionary.
  public let cache: KSCache
  /// ...

Then there’s global object called AppEnvironment that manages all these Environment in a stack

public struct AppEnvironment {
   A global stack of environments.
  fileprivate static var stack: [Environment] = [Environment()]

   Invoke when an access token has been acquired and you want to log the user in. Replaces the current
   environment with a new one that has the authenticated api service and current user model.

   - parameter envelope: An access token envelope with the api access token and user.
  public static func login(_ envelope: AccessTokenEnvelope) {
      apiService: current.apiService.login(OauthToken(token: envelope.accessToken)),
      currentUser: envelope.user,
      koala: current.koala |> Koala.lens.loggedInUser .~ envelope.user

   Invoke when we have acquired a fresh current user and you want to replace the current environment's
   current user with the fresh one.

   - parameter user: A user model.
  public static func updateCurrentUser(_ user: User) {
      currentUser: user,
      koala: current.koala |> Koala.lens.loggedInUser .~ user

  public static func updateConfig(_ config: Config) {
      config: config,
      koala: AppEnvironment.current.koala |> Koala.lens.config .~ config

  // Invoke when you want to end the user's session.
  public static func logout() {
    let storage = AppEnvironment.current.cookieStorage

      apiService: AppEnvironment.current.apiService.logout(),
      cache: type(of: AppEnvironment.current.cache).init(),
      currentUser: nil,
      koala: current.koala |> Koala.lens.loggedInUser .~ nil

  // The most recent environment on the stack.
  public static var current: Environment! {
    return stack.last


Then whenever there’s event that triggers dependencies update, we call it like

  .observeValues { [weak self] accessTokenEnv in

The cool thing about Environment is that we can store and retrieve them

// Returns the last saved environment from user defaults.
public static func fromStorage(ubiquitousStore: KeyValueStoreType,
                                 userDefaults: KeyValueStoreType) -> Environment {
  // retrieval


And we can mock in tests

  apiService: MockService(
    fetchDiscoveryResponse: .template |> DiscoveryEnvelope.lens.projects .~ [