The shortest Silver Challenge Solution

#1

Hi everyone!
Here is my solution
BNRHypnosisView.m

//Segment setup
    UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"Red", @"Blue", @"Green"]];
    segmentedControl.frame = CGRectMake(35, 200, 250, 50);
    [segmentedControl addTarget:self action:@selector(changeColor:) forControlEvents:UIControlEventValueChanged];
    [self addSubview:segmentedControl];

...

-(void) changeColor:(id)sender{
    UISegmentedControl *segmentedControl = (UISegmentedControl *)sender;
    if(segmentedControl.selectedSegmentIndex == 0){
        self.circleColor = [UIColor redColor];
	}
	if(segmentedControl.selectedSegmentIndex == 1){
        self.circleColor = [UIColor blueColor];
	}
    if(segmentedControl.selectedSegmentIndex == 2){
        self.circleColor = [UIColor greenColor];
	}

}

But when I hit the button it becomes blue (selected) and stays like selected if I hit the second or third. Why it’s not being unselected after I hit another button.

Thanks!

#2

I have the same problem.

You have probably created the UISegmentedControl in drawRect: method. So each time you touch the view, the drawRect: method is called (because the color changes) and you have a new instance of UISegmentedControl in your view in top of the previous one.

#3

I declared my UISegmentedControl as a property and then did a simple ‘for’ check in the drawRect method to avoid this problem

if (!self.control) { self.control = [[UISegmentedControl alloc] initWithItems:@[@"Red", @"Blue", @"Green"]]; _control.frame = CGRectMake(35, 200, 250, 50); [_control addTarget:self action:@selector(changeColor:) forControlEvents:UIControlEventValueChanged]; [self addSubview]; }

#4

Good solution, thank you for posting.

I was trying to add the segment control to BNRHypnosisiViewController view…as per the instructions in the challenge and I struggled to access the circleColor property from the view controller view.

Your solution seems to make more sense and it works.

Has anyone managed to solve the challenge within the BNRHypnosisiViewController view?

#5

Yes, All my code is inside BNRHypnosisViewController, I accessed the circleColor by casting.

[code]- (instancetype) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if ( self ) {
// Set the tab bar item’s title
self.tabBarItem.title = @“Hypnotize”;
// Create the UIImage from a file
// This will use Hypno@2x.png on retina display image.
UIImage *image = [UIImage imageNamed:@“Hypno.png”];
// Put that image on the tab bar item;
self.tabBarItem.image =image;

    UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:(NSArray *)@[@"Red",@"Green", @"Blue"]];
    segmentedControl.frame = CGRectMake(35, 200, 250, 50);
    segmentedControl.selectedSegmentIndex = 0;
    [segmentedControl addTarget:self
                         action:@selector(changeColor:)
               forControlEvents:UIControlEventValueChanged];
    [self.view addSubview:segmentedControl];
    
}
return self;

}

  • (void)changeColor:(id)sender
    {
    UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
    NSLog(@“The Segment controller was touched %d”, segmentedControl.selectedSegmentIndex);
    if(segmentedControl.selectedSegmentIndex == 0){
    ((BNRHypnosisView *)self.view).circleColor = [UIColor redColor];
    }
    if(segmentedControl.selectedSegmentIndex == 1){
    ((BNRHypnosisView *)self.view).circleColor = [UIColor greenColor];
    }
    if(segmentedControl.selectedSegmentIndex == 2){
    ((BNRHypnosisView *)self.view).circleColor = [UIColor blueColor];
    }
    }[/code]
#6

[quote=“aartip”]Yes, All my code is inside BNRHypnosisViewController, I accessed the circleColor by casting.

[code]- (instancetype) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if ( self ) {
// Set the tab bar item’s title
self.tabBarItem.title = @“Hypnotize”;
// Create the UIImage from a file
// This will use Hypno@2x.png on retina display image.
UIImage *image = [UIImage imageNamed:@“Hypno.png”];
// Put that image on the tab bar item;
self.tabBarItem.image =image;

    UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:(NSArray *)@[@"Red",@"Green", @"Blue"]];
    segmentedControl.frame = CGRectMake(35, 200, 250, 50);
    segmentedControl.selectedSegmentIndex = 0;
    [segmentedControl addTarget:self
                         action:@selector(changeColor:)
               forControlEvents:UIControlEventValueChanged];
    [self.view addSubview:segmentedControl];
    
}
return self;

}

  • (void)changeColor:(id)sender
    {
    UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
    NSLog(@“The Segment controller was touched %d”, segmentedControl.selectedSegmentIndex);
    if(segmentedControl.selectedSegmentIndex == 0){
    ((BNRHypnosisView *)self.view).circleColor = [UIColor redColor];
    }
    if(segmentedControl.selectedSegmentIndex == 1){
    ((BNRHypnosisView *)self.view).circleColor = [UIColor greenColor];
    }
    if(segmentedControl.selectedSegmentIndex == 2){
    ((BNRHypnosisView *)self.view).circleColor = [UIColor blueColor];
    }
    }[/code][/quote]

This works great, the only thing that needs to be done is to move the declaration of “circleColor” property from .m file to the header file.

Thank you!

#7

After pondering this challenge for a little while and getting nowhere, I read the forum for the solution.

This ‘casting’ solution is definitely pretty simple, but it didn’t make intuitive sense to me.

I initially set out to do all the coding in the view controller.

My problem was accessing the backgroundView object in the segment controller’s target method (without resorting to this casting method).

My backgroundView objects were all ‘nil’, so the color wouldn’t update.

Then I changed the addTarget object from self to self.backgroundView.

THen I implemented the action method in BNRHypnosisView.m and it worked! :slight_smile:

#8

I found a way to doing it without having to change BNRHypnosisView, instead I used Key-Value Coding to change the color of the circles. Figured that was a big hint cause it was the topic right after the challenge.

All of these changes where in BNRHypnosisViewController.m

- (void) loadView
{
    CGRect frame = [UIScreen mainScreen].bounds;
    BNRHypnosisView *backgroundView = [[BNRHypnosisView alloc] initWithFrame:frame];
    self.view = backgroundView;
    
    //create the Segmented control
    UISegmentedControl *colorSwitcher = [[UISegmentedControl alloc] initWithItems:@[@"Red", @"Blue", @"Green"]];
    
    //Update the position
    CGRect segframe = colorSwitcher.frame;
    segframe.origin.x = (frame.size.width / 2) - segframe.size.width / 2;
    segframe.origin.y = 25;
    [colorSwitcher setFrame];
    
    //Update the color for better readbility
    colorSwitcher.tintColor = [UIColor blackColor];
    
    //Add an action for when the segmented controll value changes
    [colorSwitcher addTarget:self action:@selector(colorChange:) forControlEvents:UIControlEventValueChanged];

    //add it to the view
    [self.view addSubview:colorSwitcher];
}
- (void) colorChange: (id) sender
{
    UISegmentedControl *colorSwitcher = (UISegmentedControl *) sender;
    switch (colorSwitcher.selectedSegmentIndex) {
        case 0:
            [((BNRHypnosisView *)self.view) setValue:[UIColor redColor] forKey:@"circlecolor"];
            break;
        case 1:
            [((BNRHypnosisView *)self.view) setValue:[UIColor blueColor] forKey:@"circlecolor"];
            break;
        case 2:
            [((BNRHypnosisView *)self.view) setValue:[UIColor greenColor] forKey:@"circlecolor"];
            break;
        default:
            break;
    }
}
#9

[quote=“dorrin”]I found a way to doing it without having to change BNRHypnosisView, instead I used Key-Value Coding to change the color of the circles. Figured that was a big hint cause it was the topic right after the challenge.

All of these changes where in BNRHypnosisViewController.m

- (void) loadView
{
    CGRect frame = [UIScreen mainScreen].bounds;
    BNRHypnosisView *backgroundView = [[BNRHypnosisView alloc] initWithFrame:frame];
    self.view = backgroundView;
    
    //create the Segmented control
    UISegmentedControl *colorSwitcher = [[UISegmentedControl alloc] initWithItems:@[@"Red", @"Blue", @"Green"]];
    
    //Update the position
    CGRect segframe = colorSwitcher.frame;
    segframe.origin.x = (frame.size.width / 2) - segframe.size.width / 2;
    segframe.origin.y = 25;
    [colorSwitcher setFrame];
    
    //Update the color for better readbility
    colorSwitcher.tintColor = [UIColor blackColor];
    
    //Add an action for when the segmented controll value changes
    [colorSwitcher addTarget:self action:@selector(colorChange:) forControlEvents:UIControlEventValueChanged];

    //add it to the view
    [self.view addSubview:colorSwitcher];
}

[code]

  • (void) colorChange: (id) sender
    {
    UISegmentedControl *colorSwitcher = (UISegmentedControl *) sender;
    switch (colorSwitcher.selectedSegmentIndex) {
    case 0:
    [((BNRHypnosisView *)self.view) setValue:[UIColor redColor] forKey:@“circlecolor”];
    break;
    case 1:
    [((BNRHypnosisView *)self.view) setValue:[UIColor blueColor] forKey:@“circlecolor”];
    break;
    case 2:
    [((BNRHypnosisView *)self.view) setValue:[UIColor greenColor] forKey:@“circlecolor”];
    break;
    default:
    break;
    }
    }
    [/code][/quote]

this is a great solution.
But just one thing, in the colorChange method, you write all the forkey: @“circlecolor” in lowercase, they should be in uppercase, lol

#10

Mine:

  1. create a new XIB file with a blank View, add a SegmentedControl with 3 segments, then set up proper connections for View (HypnosisView) and File’s Owner (HypnosisViewController) (i guess i was too lazy to think how to code them accordingly)

  2. remove void loadView from HypnosisViewController.m

  3. add a new property in class-extension of HypnosisView.m

  1. add corresponding method for the Segmented Control action

-(IBAction)setSegControl:(UISegmentedControl *)segControl { NSArray *colors = [[NSArray alloc]initWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil]; self.circleColor = colors[segControl.selectedSegmentIndex]; }

#11

[quote=“Vutran”]

-(IBAction)setSegControl:(UISegmentedControl *)segControl { NSArray *colors = [[NSArray alloc]initWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil]; self.circleColor = colors[segControl.selectedSegmentIndex]; }[/quote]

Oh, I like that! That’s really neat. I hope I can remember how to do that in future.