Objective C State Machine

Im currently working on a game in which the user interface has quite a number of possible states, with certain sprites being enabled, disabled, visible or invisible depending on the what the user touches on screen.

Rather than coding all of the UI state logic into a view controller or helper class, I decided to put together a simple state machine instead. It seemed to work for my current app quite well, and I reckon its something that will come in handly in the future.

You can find the source code here:
http://code.google.com/p/objective-c-state-machine/

So How do you use it?

Each state is represented by a StateInfo object, which has a name, a set of transitions, and a selector to execute when the state is entered.

@interface StateInfo : NSObject
{
NSString* _stateName;
NSMutableArray* _transitions;
SEL _selector;
}
@property (nonatomic, retain) NSMutableArray* transitions;
@property (nonatomic, retain) NSString* stateName;
@property (nonatomic) SEL selector;
-(id) initWithStateName:(NSString*)stateName;
-(StateInfo*) executeTransition:(id)anObject;
-(BOOL) canExecuteTransition:(id)anObject;
-(void) registerNextState:(StateInfo*)nextState withCondition:(NSString*)condition;
@end

The collection of transitions is made up of Transition objects, each with a condition and a StateInfo object pointing to the next state. Underneath, the condition uses an NSPredicate object, so the format for specifying the condition should follow the NSPredicate syntax.

@interface Transition : NSObject
{
NSString* _condition;
StateInfo* _nextState;
}
@property (nonatomic,retain) NSString* condition;
@property (nonatomic, retain) StateInfo* nextState;
-(id)initWithCondition:(NSString*)condition andState:(StateInfo*)state;
-(StateInfo*)execute:(id)anObject;
@end

The StateMachine object is then a simple set of states and a pointer to the current state.

@interface StateMachine : NSObject {
NSMutableArray* _states;
StateInfo* _currentState;
}
@property (nonatomic, assign) StateInfo* currentState;
@property (nonatomic, retain) NSMutableArray* states;
-(id)initWithInitialState:(StateInfo*)state;
-(void) registerState:(StateInfo*)state;
-(StateInfo*) nextState:(id)anObject;
-(void) registerInitialState:(StateInfo*)state;
-(BOOL) canTransition:(id)anObject;
-(BOOL) isCurrentState:(NSString*)stateName;
@end

The main method for the StateMachine is called nextState, and its called by passing a target object to test the transitions against, e.g.

StateMachine* stateMachine = [[StateMachine alloc] initWithInitialState:initialState];
...
[stateMachine nextState:targetObject];

When its called, the StateMachine tests the condition of each transition in the currentState against targetObject.

If a transitions condition is true, Transition.nextState becomes StateMachine.currentState, and the currentState selector is performed in the targetObject.

To setup a statemachine its pretty simple, create a statemachine object, then register the states one by one….

 StateInfo* initialState = [[StateInfo alloc] initWithStateName:@"initialState"];
StateMachine* stateMachine = [[StateMachine alloc] initWithInitialState:initialState];
StateInfo* state1 = [[StateInfo alloc] initWithStateName:@"state1"];
state1.selector = @selector(state1Method);
//--register the next state for the initial state
[initialState registerNextState:state1 withCondition:@"TRUEPREDICATE"];

The project on google code contains a sample objective-c application that uses the state machine. To get the code, use svn at the command line….
svn checkout http://objective-c-state-machine.googlecode.com/svn/trunk/ objective-c-state-machine-read-only