Location Picker is a view controller that reduces an array of Locations to a single Location. [Location] -> Location
Effects are prioritized over events and their handlers. The view controller is seen as an implementation detail of achieving a reduced list.
struct ViewModel {
struct Location {
let coordinate: CLLocationCoordinate2D
let isSelected: Bool
}
let locations: [Location]
}
class ViewController {
let input: ViewModel
let output: (ViewModel) -> Void
}
Versus a more traditional interface which usually doesn't make its resposibility as clear or public.
class ViewController {
init() {}
func viewDidLoad() {}
func didSelectRowAtIndex(index: Int) {}
}
A value-orientation seperates concerns more evidently and prevents the view controller from becoming involved in the details of the orgin/destination of its inputs/outputs and results in a component that is more modular and reuseable.
Commands are expressed as values leaving the caller free from having to know how to acheive the desired effect (what to call and when). Traditional interfaces are prodecuraly coupled and calling commands out of order can produce issues.
viewController.load()
viewController.request = Request(query: "near Boston")
viewController.indicatorColor = .blue
The use of a declarative interface internalizes the responsibility of knowing the correct order of operation.
viewController.input = Model(
state: .loading(Request(query: "near boston")),
indicatorColor: .blue
)
On callback (-layoutsubviews, -didInteractWithControl) the view controller returns only a suggested model. The caller must reinject the suggestion as a command in order for it to render. Because of this, state travels on a single predictable path from a single source of truth.
Command -> Suggestion -> Validation? -> Command
The combination of a linear path and commands-as-values allows for observability which allows for features like:
- Testing
- State Restoration (from a previous session, undo-manager)
- State Playback (animated feature-tutorials, analytics replays, crash replays)
Just for fun, state is recorded with a timestamp and made available for playback via re-injection. Note: The first half of this GIF is the user's interaction and the second, the playback of that interaction.