Silver Challenge - using a XIB


#1

According to the text:
“When a view controller’s view has subviews, it is best to create and load its view hierarchy in a XIB file instead of overriding loadView. Creating a view programmatically or from a XIB doesn’t make any difference once the application is running; a XIB file is just easier when you need to lay out multiple view objects.”

In an effort to understand this better, I decided to refactor the code to include a HypnosisViewController.xib file. Unfortunately, I have run into an issue. I can’t get HypnosisView class to initialize. I can get it to draw on the window but the circles are black instead of any color I assign. Steps I took:

  1. Created a XIB file and called it HypnosisViewController.xib (to match the view controller name)
  2. Added a UIView(subview) to XIB created view
  3. Added a segmented control to the View(top level) - I now have a view with a 2 subviews.
  4. Assigned the UIView(subview) the HypnosisView class (in the custom class field)
  5. Created an IBOutlet

[code]#import <Foundation/Foundation.h>

@interface HypnosisViewController : UIViewController
{
__weak IBOutlet UISegmentedControl *colorControl;
__weak IBOutlet UIView *hypnoView;

}

-(IBAction)changeCircleColor:(id)sender;

@end
[/code]

  1. I made all the appropriate connections in IB. (at least I think)
  2. In my changeCircleColor method I wrote the following code:

[code]-(IBAction)changeCircleColor:(id)sender {
if ([colorControl selectedSegmentIndex] == 0) {
NSLog(@“set the color to red”);
//[hypnoView setHidden:YES];
HypnosisView *v = [[HypnosisView alloc] initWithFrame:hypnoView.frame];
[v setCircleColor:[UIColor redColor]];

} 
else if ([colorControl selectedSegmentIndex] == 1) {
    NSLog(@"set the color to green");
}
else if ([colorControl selectedSegmentIndex] == 2) {
    NSLog(@"set the color to blue");
}

}
[/code]

Now, the problem is when the app runs, it doesn’t hit the designated initializer for HypnosisView class. It bypasses it and goes straight to the drawRect: method. I have made an error in the connections or in calling the HypnoView class. Any thoughts, suggestions?

(Pardon my ignorance in terminology, I am a designer playing in a developers sandbox. the toys are still new to me :smiley: )

output on simulator screen:
cl.ly/2t3Y2T1O160r1H2M3L1S


#2

I got this working, but I’m not sure how correct it is.

What I did:

  1. Deleted loadView in HypnosisViewController.m, created a HypnosisViewController.xib file and set the File’s Owner class to HypnosisView
  2. Added a UIView and set it as the view for File’s Owner (so this is the HypnosisViewController’s root view)
  3. Set the UIView’s class to HypnosisView
  4. Added a IBOutlet for the HypnosisView and IBAction for change color in the HypnosisViewController.h

[code]@interface HypnosisViewController : UIViewController
{
__weak IBOutlet HypnosisView *hv;
}

  • (IBAction)changeColor:(id)sender;[/code]
  1. Connected the HypnosisView UIView to IBOutlet hv - the UIView now is connected to view (step 2) and hv
  2. Added UISegmentedControl in the XIB file with Blue, Red, Green segments under the UIView
  3. Connected the UISegmentedControl to the IBAction changeColor
  4. Added the changeColor code to HypnosisViewController.m

-(IBAction)changeColor:(id)sender { NSInteger tabSelected = [sender selectedSegmentIndex]; if (tabSelected == 0) { [hv setCircleColor:[UIColor blueColor]]; } else if (tabSelected == 1) { [hv setCircleColor:[UIColor redColor]]; } else if (tabSelected == 2) { [hv setCircleColor:[UIColor greenColor]]; } }

While this works, I feel like there should be a way to do this without having the UIView connected to view and the IBOutlet hv. I need the IBOutlet hv in order to use the setCircleColor method though. Any thoughts?


#3

Segmented Control works. But like Syndrome said, the initializer didn’t work, thus the color of the circles is black when the app loads.
Tried what BillyShih suggested, but that doesn’t fix the initializer problem neither.

Can anyone help with how to (or rather where to) put the initializer so the initial color can be set?

Thanks


#4

I inserted the line

[quote] [HypnoView setCircleColor:[UIColor redColor]];
[/quote]

in the (void)viewDidLoad: method.

I don’t know if it’s correct, because the initWithNibName:bundle: method is indeed not called, but at least I’m sure the viewDidLoad: method is …


#5

I set the color in HypnosisViewController.m

- (void)viewDidLoad { [super viewDidLoad]; [hypnosisView setBackgroundColor:[UIColor clearColor]]; [hypnosisView setCircleColor:[UIColor redColor]]; NSLog(@"HypnosisViewController loaded its view"); }


#6

I just wanted to add that I also did the Silver challenge using a XIB file. It was somewhat similar to the other solutions kicked around here.

  • create a HypnosisViewController.xib
  • add a UIView to this which will be the HypnosisView (and thus its class should be set to HypnosisView rather than plain old UIView)
  • and the second view added is the segmented control

Link the HypnosisView view to an instance variable that you set in the HypnosisViewController (ctrl-drag).

Link the segmented control to a segmented control IBAction… which I’ve made a little overly-complex since I wanted to have it be able to go back to Gray:

[code]- (IBAction)selectCirclesColor:(UISegmentedControl *)sender {
// In this version, I have the action depend on the text of the button in the control. Because
// of this, it was easier to extend to a general case, i.e. for Gray.
// Slightly annoyed that there isn’t a “get the Title of the currently selected segment” method.

NSUInteger indx = sender.selectedSegmentIndex;
NSString *currentTitle = [sender titleForSegmentAtIndex:indx];
if ([currentTitle isEqualToString:@"Red"])
{ 
    [hypnoView setCircleColor:[UIColor redColor]]; 
    [sender setTitle:@"Gray" forSegmentAtIndex:indx];
    // deselect any selection
    sender.selectedSegmentIndex = -1;
}
else if ([currentTitle isEqualToString:@"Blue"])
{
    [hypnoView setCircleColor:[UIColor blueColor]];
    [sender setTitle:@"Gray" forSegmentAtIndex:indx];
    sender.selectedSegmentIndex = -1;
}
else if ([currentTitle isEqualToString:@"Green"])
{
    [hypnoView setCircleColor:[UIColor greenColor]];
    [sender setTitle:@"Gray" forSegmentAtIndex:indx];
    sender.selectedSegmentIndex = -1;
}
else if ([currentTitle isEqualToString:@"Gray"])
{
    [hypnoView setCircleColor:[UIColor lightGrayColor]];
    if (indx == 0) [sender setTitle:@"Red" forSegmentAtIndex:indx];
    else if (indx == 1) [sender setTitle:@"Blue" forSegmentAtIndex:indx];
    else if (indx == 2) [sender setTitle:@"Green" forSegmentAtIndex:indx];
    sender.selectedSegmentIndex = -1;
}

}
[/code]
Getting your head around programmatically solving problems, as well as via IB, is fun. I have a slight leaning towards the IB methodology, being more graphical, more UI-oriented. But maybe that only applies when you are using bog-standard controls an interface elements.