For a command that initiates a network request when:
- The network connection is up (precondition)
- The network request is not already in progress (enforced serialization)
The lifecycle proceeds as follows:
- The view model exposes the command and describes its behavior
- The view binds the command to a control
- The control will automatically be enabled when the command's preconditions (above) pass
- When the control is clicked, the command is executed
- When results arrive from the network, the view model handles them
- The view model eventually fires some property or notification to update the view
Setup:
VM (creates command) ---> (passed to) View ---> (passed to) Control
Execution:
Control ---> Command ---> VM ---> View
- The view doesn't need to know when the command is valid, since the control is automatically enabled/disabled via its
rac_command
extension - The command can be bound to multiple input sources in exactly the same way
- The command can be directly executed while preserving all of its guarantees
- The view doesn't need to know anything about the behavior that will occur, since it does not directly receive the results of the command
- The view can present errors (via
RACCommand.errors
) without caring why or how they occurred - Signals are automatically delivered to the main thread, which helps avoid bugs in UI code
- Receiving results is confusing, because signals of signals (like
executionSignals
) are confusing - Views have access to more information about the command than they need, like
executionSignals
,allowsConcurrentExecution
, etc. - The relationship between the
signalBlock
and execution is unclear - The view model should respond to the view out-of-band (this is simpler, but occasionally makes things harder as well)
Not sure if it's something you want to call out here, but there's also the behavior of commands with respect to subscribing and delivering on the main thread scheduler. Some clients may have come to expect this.