Mobius.swift Documentation

repository·master·Indexed 20 days ago

https://github.com/spotify/mobius.swift

A functional reactive framework for Swift and the Apple ecosystem designed for managing state evolution and side-effects. Mobius isolates stateful logic from side-effect execution using a loop consisting of a Model, Events, an Update Function, and Effects/Effect Handlers to improve testability and separation of concerns.

Tokens
816
Snippets
2
Records
4
Agent score
20%

What's inside Mobius.swift

  1. How Mobius state management works

    master

    Mobius manages application state through a functional reactive loop consisting of four core concepts:

    1. Model: A data structure representing a snapshot of your application state (e.g., an Int, a struct, or an enum).
    2. Events: Messages sent to the framework to request a state change (e.g., an enum representing user actions).
    3. Update Function: A pure function that takes the current Model and an Event and returns the next state. To handle side effects, it returns a Next<Model, Effect> type.
    4. Effects & Effect Handlers: Effects are descriptions of side effects to be performed (e.g., playing a sound, network calls). Effect Handlers are the components that actually execute these effects.

    By separating the logic of what should happen (the update function) from how it happens (the Effect Handler), Mobius ensures high testability and separation of concerns.

    // Example of the core loop structure
    let application = Mobius.loop(update: update, effectHandler: effectHandler)
        .start(from: initialModel)
    
    application.dispatchEvent(.someEvent)
  2. Install Mobius.swift via Swift Package Manager

    master

    You can add Mobius to your Apple platform project using the Swift Package Manager. Add the following dependency to your Package.swift file:

    .package(url: "https://github.com/spotify/Mobius.swift", from: "0.5.0")
  3. Build a counter with Mobius

    master

    This example demonstrates the complete lifecycle of a Mobius application: defining a model, events, effects, an update function, an effect handler, and starting the loop.

    // 1. Define the Model
    typealias CounterModel = Int
    
    // 2. Define the Events
    enum CounterEvent {
        case increment
        case decrement
    }
    
    // 3. Define the Effects
    enum CounterEffect {
        case playSound
    }
    
    // 4. Define the Update function
    // Returns 'Next' to allow for state transitions and side effects
    func update(model: CounterModel, event: CounterEvent) -> Next<CounterModel, CounterEffect> {
        switch event {
        case .increment: 
            return .next(model + 1)
        case .decrement:
            if model == 0 {
                return .dispatchEffects([.playSound])
            } else {
                return .next(model - 1)
            }
        }
    }
    
    // 5. Define the Effect Handler
    import AVFoundation
    
    private func beep() {
        AudioServicesPlayAlertSound(SystemSoundID(1322))
    }
    
    let effectHandler = EffectRouter<CounterEffect, CounterEvent>()
        .routeCase(CounterEffect.playSound).to { beep() }
        .asConnectable
    
    // 6. Start the Mobius loop
    let application = Mobius.loop(update: update, effectHandler: effectHandler)
        .start(from: 0)
    
    // Usage:
    application.dispatchEvent(.increment) // Model is now 1
    application.dispatchEvent(.decrement) // Model is now 0
    application.dispatchEvent(.decrement) // Sound effect plays! Model is still 0