Silver Challenge


#1

I’d like to share my solution to the silver challenge with the group. Please let me know how I might improve it.

Please note that if the HypnosisView is destroyed by simulating a memory warning, it will revert to its original Gray state regardless of the last color selected. Although I really enjoyed this challenge, I’m too brain-dead at the moment to attempt to fix that. :slight_smile:

I made changes to 2 files: HypnosisViewController.h and HypnosisViewController.m.

In HypnosisViewController.h, I added the following line:

I realize that IBAction is typedefed to void but I like that I can visually identify the method as an action method.

In HypnosisViewController.m I changed the “loadView” method to add the UISegmentedControl and to configure its appearance and position on the screen. Here’s the method:

[code]- (void) loadView
{
// Create View
CGRect screenFrame = [[UIScreen mainScreen] bounds];
HypnosisView *hView = [[HypnosisView alloc] initWithFrame: screenFrame];

// Create SegmentedControl & set the first tab to be "selected". This is our default Gray color.
NSArray *segmentLabels = @[@"Gray", @"Red", @"Green", @"Blue"];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:segmentLabels];
[segmentedControl setSegmentedControlStyle: UISegmentedControlStyleBar];
[segmentedControl setSelectedSegmentIndex:0];

// Center the SegmentedControl at the top of our screen
CGRect scFrame = [segmentedControl frame];

// NSLog(@“Frame Origin x [%f] y[%f] Size w [%f] h [%f]”, scFrame.origin.x, scFrame.origin.y, scFrame.size.width, scFrame.size.height);
scFrame.origin.y = 0; // already at 0 but set it anyway, just to be safe
scFrame.origin.x = (screenFrame.size.width - scFrame.size.width) / 2.0;
[segmentedControl setFrame:scFrame];

// Register [self changeCircleColor] method to receive "ValueChanged" notifications
[segmentedControl addTarget:self action:@selector(changeCircleColor:) forControlEvents:UIControlEventValueChanged];

// Add the SegmentedControl as a subview of our main view
[hView addSubview:segmentedControl];

// Set the HypnosisView as *the* view of this controller
[self setView:hView];

}[/code]

Finally, I implemented the “changeCircleColor” method in HypnosisViewController.m as follows:

[code]- (IBAction)changeCircleColor:(id)sender
{
// NSLog(@“In method changeCircleColor”);
HypnosisView *hview = (HypnosisView *)[self view];

switch ([sender selectedSegmentIndex]) {
    case 0: {   // Gray
        NSLog(@"Setting Color to Gray");
        [hview setCircleColor: [UIColor lightGrayColor]];
        break;
    }
    case 1: {   // Red
        NSLog(@"Setting Color to Red");
        [hview setCircleColor: [UIColor redColor]];
        break;
    }
    case 2: {   // Green
        NSLog(@"Setting color to Green");
        [hview setCircleColor: [UIColor greenColor]];
        break;
    }
    case 3: {   // Blue
        NSLog(@"Setting color to Blue");
        [hview setCircleColor: [UIColor blueColor]];
        break;
    }
    default: {  // This should never get executed
        NSLog(@"HOUSTON, WE HAVE A PROBLEM!!!");
        break;
    }
}

}[/code]


#2

There is a better way than to use CASE


#3

This is great and very similar to my own solution except I got stuck with not being able to access the HypnosisView from my (IBAction) method. You used a line that I don’t quite understand:

HypnosisView *hview = (HypnosisView *)[self view];

How does the (HypnosisView *) bit make it work?

Hope you can help.

Many thanks


#4

Your code doesn’t work for me. I get the Log messages “setting color to red”, “setting color to green”, etc. logged to the console, but the color on the screen isn’t actually changing. What could I be missing?


#5

Post the contents of your files in this thread and we can take a quick peak.


#6

Since this continues from the exercise in Chapter 6, I went back and skimmed through Chapter 6, and noticed that the “shake device” to turn the lines red from Chapter 6 wasn’t working either (I suppose I just forgot to test that at the time). Anyways, I just took the completed examples form the .zip file that they have on their website, and added your code to it, and it works fine now. I guess I must have missed some code in Chapter 6 along the way somewhere.


#7

[quote=“jamesbb”]HypnosisView *hview = (HypnosisView *)[self view];

How does the (HypnosisView *) bit make it work?[/quote]

This line will create a pointer to the HypnosisView. You need this in order to make changes to the view, in other words it would solve the problem you are having with not being able to access the HypnosisView.

The return type of [self view] is UIView*. You need to specify that you are pointing to an instance of HypnosisView, that’s what the (HypnosisView *) will do. If not, you will get a warning.


#8

I was looking at this solution, I like it because it’s pretty straight forward but decided I didn’t like the cast
HypnosisView *hview = (HypnosisView *)[self view];

So, at the top of HynosisViewController.m, just after the imports I added a class extension for a private variable:

@interface HypnosisViewController () @property (nonatomic, weak) HypnosisView *hypnoView; @end

Also in the loadView method

[code] // Create a view
CGRect frame = [[UIScreen mainScreen] bounds];
HypnosisView *hv = [[HypnosisView alloc] initWithFrame:frame];
[self setHypnoView:hv];

(...)

// Set it as *the* view of this view controller
[self setView:[self hypnoView]];

[/code]

and in changeCircleColor I got rid of the cast and replaced it with

[code] switch ([sender selectedSegmentIndex]) {
case 0: { // Gray
NSLog(@“Setting Color to Gray”);
[[self hypnoView] setCircleColor: [UIColor lightGrayColor]];
break;
}

    (...)

[/code]