A finite state machine (FSM) is a mathematical model of computation. An FSM can be described as a set of relations of the form:
If we are in state
S
and the eventE
occurs, we should perform the actionsA
and make a transition to the stateS'
.
Using a finite state machine helps us to reason about the code and the application state at all times with absolute certainty. Apple's GameplayKit library has built-in FSM classes GKStateMachine
and GKState
using which we can model an FSM.
Here I will describe how to use an FSM for UI state transitions for an iOS app. I will use an example of how I have used it in my own app API Tester Pro to model the request-response screens. This is the screen which is a bit complex with a few states it can be in than other screens which are direct transition from one screen to another. I had used FSM only in this particular section of the UI as setting up these classes involves a certain degree of complexity.
This is the main state machine class. The state machine is associated with a request. So it takes an ERequest
object and RequestManager
is the class which handles the events and actions.
This is the full code for various states the app can be in for a request. There are only four states which are RequestPrepareState
, RequestSendState
, RequestResponseState
and RequestCancelState
. For each GKState
we can see the possible next states it can be in. And the state machine will transition according to these rules only. RequestResponseState
is the final state and it doesn't require RequestCancelState
. Other states takes RequestCancelState
because at any time user can cancel the ongoing request.
RequestTableViewController
is the class which instantiates the RequestManager
which has the logic to manage the state and actions associated with each state. When user taps the go
button the FSM enters its first state which is RequestPrepareState
which is done using the man.start()
call.
In this RequestManager
class we can see the state progression. I am showing only the relevant code for brevity.
-
First it enters
RequestPrepareState
. On entering this state thedidEnter()
method will be invoked by GameplayKit. Here we call theman.prepareRequest()
where the request is processed, extrapolated and a finalURLRequest
object is returned by the methodfunc requestToURLRequest(_ req: ERequest) throws -> URLRequest?
. Then it moves toRequestSendState
. -
In the
RequestSendState
, it callsman.sendRequest(urlReq)
which sends theURLRequest
object using theEAHTTPClient
class. It is an async function and when the response is obtained, it will invoke theresponseDidObtain()
function where the response is processed and saved. It then moves toRequestResponseState
. -
In the
RequestResponseState
which is entered after a response to the request is obtained, we display the result in the UI usingman.viewResponseScreen(data: data)
, be it a success or an error. -
Then there is
RequestCancelState
which is entered when user cancels an ongoing request which sends a notification to cancel the existing request.
Using finite state machines will help us build robust applications. I must say, GameplayKit is just splendid.