cs193p – Assignment #2 Extra Task #1

Please note, this blog entry is from a previous course. You might want to check out the current one.

Add a UISlider to your UI which travels through the history of the results of the currently-being-played game’s card choices and display it to the user (moving the slider will modify the contents of the text label you created for Required Task 5 to show its state over the course of the game). When you are displaying past results, you probably want the text label to be grayed out or some such (take a look at the UIView method alpha and note that UISlider inherits from UIView) so it’s clear that it’s “the past.” And every time a new choice happens, you probably want to “jump to the present” in the slider. Implementing this extra credit item will require you to familiarize yourself with UISlider’s API and to add a data structure to your Controller to keep track of the history. It can be implemented in fewer than a dozen lines of code.

The history of previous card flips has nothing to do with the model, thus we a will add this feature in the view control. First create an array property to hold the history and use lazy instantiation:

@property (strong, nonatomic) NSMutableArray *flipHistory;
- (NSMutableArray *)flipHistory
    if (!_flipHistory) {
        _flipHistory = [NSMutableArray array];
    return _flipHistory;

When the deal button gets pressed reset the history array:

- (IBAction)touchDealButton:(UIButton *)sender {
    self.flipHistory = nil;

Add a slider in storyboard, set its range to 0 (because at the beginning we have no history to show) and adjust its tint to your liking:

cs193p – assignment #2 extra task #1 - slider
cs193p – assignment #2 extra task #1 – slider

Note the “invisible” description label … adjusting the layout like here would be easier having a text there, which could be removed during initialization of the view …

Connect the slider to an outlet property and an action. By default a slider works “analog” (meaning you get comma values), but we have a discrete history, find the closest available history point and move the slider to that point. When moving the slider from the “current” position change the alpha value of the description label (making it a little bit translucent) and of course adjust its text:

@property (weak, nonatomic) IBOutlet UISlider *historySlider;
- (IBAction)changeSlider:(UISlider *)sender {
    int sliderValue;
    sliderValue = lroundf(self.historySlider.value);
    [self.historySlider setValue:sliderValue animated:NO];    
    if ([self.flipHistory count]) {
        self.flipDescription.alpha =
            (sliderValue + 1 < [self.flipHistory count]) ? 0.6 : 1.0;
        self.flipDescription.text =
        [self.flipHistory objectAtIndex:sliderValue];

After updating the description label (after a card flip) check if the description is already stored in the history and store it if needed. Because the number of stored history elements changed, the slider range needs an update:

- (void)updateUI
        self.flipDescription.text = description;
        self.flipDescription.alpha = 1;
        if (![description isEqualToString:@""] 
            && ![[self.flipHistory lastObject] isEqualToString:description]) {
            [self.flipHistory addObject:description];
            [self setSliderRange];

The code to update the slider could actually be added above, but creating a helper method adds more readability. Calculate the new maximal value for the slider, set it and move the slider to the new position:

- (void)setSliderRange
    int maxValue = [self.flipHistory count] - 1;
    self.historySlider.maximumValue = maxValue;
    [self.historySlider setValue:maxValue animated:YES];

The complete code is available on github.


9 thoughts on “cs193p – Assignment #2 Extra Task #1”

  1. Why can’t flipHistory be part of the model? I think it belongs really nicely in PlayingCardGame

    1. I see your point! But then you should really save only none-view-related information inside the history. Because use the flip history to store the description string which is generated in the view controller, my flip history just does not belong to the model …

      1. I’d find it interesting to know if it’s model or view controller actually. I totally agree one shouldn’t post view information in a hypothetical NSArray history in the model.

        The contents of this array would of course be a direct consequence of what is happening in the view. Then again so is the score and the lastChosenCards array.

        1. Let’s formulate it in another way. When it holds only information about the model and the state of the model, put it into the model. When it contains information derived from the view, but it into the view controller. When there is a lot of discussion about where do put it, just put it where you think it fits best …

          1. I’m still not convinced: I think that the model is responsible for matching and scoring, so and array of results (NSString) is at home in the model.

  2. Thanks for sharing your solutions. I have one small suggestion on this one. When the user presses the deal button, the slider range does not reset to 0 so the slider is movable but doesn’t do anything. This can be solved by adding:

    [self setSliderRange];

    immediately after setting the flipHistory to nil.

Leave a Reply

Your email address will not be published.