ViewController/State

1,063 views

Published on

A presentation view controllers and state machines.

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,063
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • ViewController/State

    1. 1. View Controllers and State A Journey
    2. 2. My Main PointMany times, view controllers haveimplicit states and, if these statesare recognized and made explicit,code may become clearer and easierto maintain.
    3. 3. The record button
    4. 4. First Try• The record button needs to turn red while the app is recording.• The recorder needs to start recording from the microphone.
    5. 5. First Try[recordButton setImage:@”black.png” forState:UIControlStateNormal];[recordButton setImage:@"red.png" forState:UIControlStateSelected];- (IBAction)recordButtonPressed:(id)sender {! UIButton *recordButton = (UIButton *)sender;! if (recordButton.selected) {! ! recordButton.selected = NO;! ! [recorder stop];! } else {! ! recordButton.selected = YES;! ! [recorder record];! }}
    6. 6. What about this?[recordButton setImage:@”black.png” forState:UIControlStateNormal];[recordButton setImage:@"red.png" forState:UIControlStateSelected];- (IBAction)recordButtonPressed:(id)sender {! UIButton *recordButton = (UIButton *)sender;! if (recorder.isRecording) {! ! recordButton.selected = NO;! ! [recorder stop];! } else {! ! recordButton.selected = YES;! ! [recorder record];! }}
    7. 7. Problems?• There are two independently maintained variables.• Normally, they are coupled together, but what if something happens so that they are not (eg. when I handle enter background, interruptions, etc. might I stop the recorder without changing the button)?
    8. 8. Add a Play Button?
    9. 9. Add a Play Button?- (IBAction)playButtonPressed:(id)sender {! UIButton *playButton = (UIButton *)sender;! if (playButton.selected) {! ! NSAssert(!recorder.isRecording, @”!!!”);! ! [player pause];! ! playButton.selected = NO;! } else {! ! [recorder stop];! ! recordButton.selected = NO;! ! [player play];! ! playButton.selected = YES;! }}
    10. 10. My Main PointMany times, view controllers haveimplicit states and, if these statesare recognized and made explicit,code may become shorter, clearerand easier to maintain.
    11. 11. State?There is a formal mathematicdefinition of states, “statemachines”, “finite state automata”that one normally studies incomputer science.
    12. 12. State?I am inspired by these ideas. Butmy priority is reducing the amountof code and the complexity of code,not in creating an implemtation of aformal state machine.
    13. 13. State?For this purpose, “states” arediscrete temporal conditions thatsomething (in this case, a viewcontroller) might be “in” which use“transitions” to move back andforth between each other.
    14. 14. State?States are intended to be mutuallyexclusive (this view controllercannot be in a record and play stateat the same time). This isrestrictive but that is actually astrength.
    15. 15. Implementing StatesImplementing states involvesrecognizing (naming) it andfiguring out how to transition intoit (and out of it?) correctly.
    16. 16. before after recording playingrecording recording
    17. 17. Using enumstypedef enum {! BeforeRecordingState,! RecordingState,! AfterRecordingState,! PlayingState} State;@interface RecordingController {! State _state;}
    18. 18. Dispatching-(void)transitionToState:(State)state {! switch(state) {! ! case BeforeRecordingState:! ! ! [self exitBeforeRecordingState:_state];! ! ! break;! ! case RecordingState:! ! ! [self exitRecordingState:_state];! ! ! break;...! ! default:! ! ! NSAssert(YES, @"unknown state!")! ! ! break;! }! _state = state;! switch(state) {! ! case BeforeRecordingState:! ! ! [self enterBeforeRecordingState];! ! ! break;... }}
    19. 19. Methods-(void)enterRecordingState {! recordButton.selected = YES;! [recorder record];}-(void)exitRecordingState:(State)nextState {! NSAssert(nextState != AfterRecordingState, @”!!!"! recordButton.selected = NO;! [recorder stop]}-(IBAction)recordButtonPressed:(id)sender {! if (_state == RecordingState) {! ! [self transitionToState:AfterRecordingState];! } else {! ! [self transitionToState:RecordingState];! !! }}
    20. 20. In GeneralI have found this kind of design isgenerally better for keeping thecomplexity of view controllersunder control.
    21. 21. My Main PointMany times, view controllers haveimplicit states and, if these statesare recognized and made explicit,code may become clearer and easierto maintain.
    22. 22. But...
    23. 23. I hate this.-(void)transitionToState:(State)state {! switch(state) {! ! case BeforeRecordingState:! ! ! [self exitBeforeRecordingState:_state];! ! ! break;! ! case RecordingState:! ! ! [self exitRecordingState:_state];! ! ! break;...! ! default:! ! ! NSAssert(YES, @"unknown state!")! ! ! break;! }! _state = state;! switch(state) {! ! case BeforeRecordingState:! ! ! [self enterBeforeRecordingState];! ! ! break;... }}
    24. 24. • The dispatch method must be unique for each view controller because each view controller has a unique collection of states.• But they are identical in logic.• This is, arguably, code duplication.
    25. 25. What if...• ...the view controller ran the transitions automatically?• ...states were blocks, not methods?• ...transitions between states were animatable?
    26. 26. What if?-(void)viewDidLoad { ...! [self addState:@"RecordingState"! ! enter:^{! ! ! recordButton.selected = YES;! ! ! [recorder record];! ! }! ! exit:^(NSString *previousState) {! ! ! recordButton.selected = NO;! ! ! [recorder stop];! ! }! ];! [self invalidateTransitionFromState:@"RecordingState" toState:@"PlayingState"];! ...
    27. 27. ChocolateBox Coming Soon to GitHub

    ×