How come I cannot override customization of XIB using initwithnibname - iphone

How come the CheckBox does not load any of the images if I do this? It only works if I set them from the XiB files. I can do this from Xib, but if I do need more complex things to customize, I won't know how.
I set a break point there so I know these things are being called.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[tcCheckBox setBackgroundImage:[UIImage imageNamed:#"checkbox-unchecked.png"] forState:UIControlStateNormal];
[tcCheckBox setBackgroundImage:[UIImage imageNamed:#"checkbox-checked.png"] forState:UIControlStateSelected];
[tcCheckBox setBackgroundImage:[UIImage imageNamed:#"checkbox-checked.png"]
forState:UIControlStateHighlighted];
tcCheckBox.adjustsImageWhenHighlighted=YES;
**// Custom initialization**
}
return self;
}

This is because initWithNibName:bundle: doesn't instantiate the nib right away but just initializes the view controller, so all your IBOutlets are still nil at this point. Override viewDidLoad for custom UI initialization, this method gets called when the nib gets instantiated and all your IB connections are resolved.

Related

InitWithNibName returns viewController but view is nil

Other xib's auto-load fine, but not this one.
When I push this viewcontroller, initWithNibName, loadView, viewDidLoad, and viewWillAppear are called fine, but the view (and all self.xxx objects in #interface) are nil in all these methods, and I am left with an empty window under the navigationbar.
SettingsMain *newVC=[[SettingsMain alloc] initWithNibName:#"SettingsMain" bundle:nil];
[self.navigationController pushViewController:newVC animated:YES];
I was wondering if I can force setting self.view to what's in the .xib, in loadView or initWithNibName, so that all the outlets etc are initalized.
The viewcontroller has the standard code,
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
The problem is that when viewDidLoad is fired, self.view is nil.

XIB is not showing / loading the scrollview but the controls added via code inside the viewdidload being shown

I have addded UIScrollView to my xib but it was not showing on to my view controller.
Also in the view did load method, I have added text boxes to the view controller. This is displayed when I push the view, but not the scrollview which I added inside the xib.
I tried to push the view in two ways
Way 1
SubscribedDetailedViewController *aDetailView = [[[SubscribedDetailedViewController alloc]initWithNibName:#"SubscribedDetailedViewController" bundle:nil]autorelease];
[self.navigationController pushViewController:aPoemDetailView animated:YES];
Way 2
SubscribedDetailedViewController *aDetailView = [[[SubscribedDetailedViewController alloc]init]autorelease];
[self.navigationController pushViewController:aPoemDetailView animated:YES];
Also I placed the below code
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
The above function also gets called.
Why the scrollview which I added into the xib is not being displayed? But the controls added via code inside the viewdidload being shown.

Passing data between views isn't working

I've done this many times with code that is exactly the same, but for some reason it isn't working today.
ExampleViewController1 *exampleView = [[ExampleViewController1 alloc] initWithNibName:#"ExampleViewController1" bundle:nil];
[exampleView setProjectName:[[self.projectListArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
NSLog(#"%#", [[self.projectListArray objectAtIndex:indexPath.row] objectForKey:#"name"]);
XAppDelegate.stackController pushViewController:exampleView fromViewController:nil animated:YES]
My NSLog prints out appropriately.
My ExampleViewController1.h file declared like:
#property(nonatomic, strong) NSString *projectName;
I then do this code in ExampleViewController1.m's
-(void)viewDidLoad {
NSLog(#"%#", self.projectName);
self.projectNameLabel.text = self.projectName;
[super viewDidLoad];
}
The results of my NSLogs are curious. The NSLog from my viewDidLoad appears to be getting called before my other one:
2012-04-22 10:59:41.462 StackedViewKit[43799:f803] (null)
2012-04-22 10:59:41.463 StackedViewKit[43799:f803] NewTest
I have confirmed that the (null) value there is from NSLog(#"%#", self.projectName);, but that should be the second NSLog called...I can't figure out why it is coming through first.
Someone requested this code:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// random color
self.view.backgroundColor = [UIColor colorWithRed:((float)rand())/RAND_MAX green:((float)rand())/RAND_MAX blue:((float)rand())/RAND_MAX alpha:1.0];
}
return self;
}
As I expected, the problem is that you are trying to access self.view inside the initialization method. So move the line self.view.backgroundColor = ... to the viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#", self.projectName);
self.projectNameLabel.text = self.projectName;
self.view.backgroundColor = [UIColor colorWithRed:((float)rand())/RAND_MAX green:((float)rand())/RAND_MAX blue:((float)rand())/RAND_MAX alpha:1.0];
}
In fact, the documentation of the view property says:
If you access this property and its value is currently nil, the view controller automatically calls the loadView method and returns the resulting view.
So when you call self.view in the initialization method, the view controller will have to load the view (from the nib or using the loadView method). And that's why viewDidLoad is called.
viewDidLoad is called before a view controller is displayed for the
first time, not immediately after initWithNibName.
> viewDidLoad method is called after the view controller has loaded its view
hierarchy into memory. This method is called regardless of whether the
view hierarchy was loaded from a nib file or created programmatically
in the loadView method.
> initWithNibName The nib file you specify is not loaded right away. It
is loaded the first time the view controller’s view is accessed. If
you want to perform additional initialization after the nib file is
loaded, override the viewDidLoad method and perform your tasks there.
You can use App delegate to pass the data from one to another, that is another alternate solution.
you do in initWithNibName method itself. or in viewDidAppear.
Your initWithNibName method should be like this as per as #sch comments;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil] //just set it here first and then check
if (self) {
// do something here;
}
return self;
}
We just need to be smart enough to think about what do we need to in constructor and what do we need to at viewDidLoad (once it had loaded into memory)

CustomViewController throughout Application

I want to display a custom bar that appears on every screen of my application with buttons that work. I add the CustomViewController to my classes in the init method, and everything works correctly, except when I analyze my application I get a potential memory leak.
When I release [customViewController release], the buttons on the CustomViewController will no longer work. What is the proper way to go about implementing this solution with no memory leaks.
#import "CustomViewController.h"
#implementation CustomViewController
- (IBAction)doSomething:(id)sender
{
// Perform an action
}
#end
A ViewController which I create the CustomViewController:
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
CustomViewController *customViewController = [[CustomViewController alloc] initWithNibName:#"CustomViewController" bundle:nil];
UIView *bar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 30)];
[bar addSubview:customViewController.view];
[self.view addSubview:bar];
[bar release];
}
}
You seem to be going about implementing this the wrong way. What you actually need to do is create CustomViewController and add your toolbar to that view. Every other view controller in your app should then be made a subclass of CustomViewController.
If a custom navigation bar is the only thing you're using this superclass for, I would recommend just styling the bar directly on the UINavigationController your app is using.
The proper solution was to create a container view, and place my custom task bar inside of that view.
You said your bar has buttons? Does it release those buttons when it itself is released? Check it's viewDidLoad function.

iPhone hand crafted views/controllers

I was wondering if anyone knew of any good online resources/tutorials for creating views and controllers programatically rather than via the interface builder. Everything I have looked at uses the interface builder and the created nibs, while the IB is ok I would like to have the option of developing these manually (both for practical reasons and get a good understanding of how it all fits together rather than the superficial one you get from dragging and dropping things).
My background is in java and I'm finding it slow and frustrating using the interface builder to develop views the way I would sometimes do them in Java, i.e. either
generate the source programatically from a domain model and then tweak the result if requried
use some meta-data and/or reflection and dynamically add the controls to the view
Also, once I have created a view is there anyway I can add it to the interface builder to make it available to use as a sub view on another view?
Thanks, Vic
The Interface Builder method creates "freeze-dried" objects that are re-created at runtime when you initialize the object from the NIB. It still does the same alloc and init stuff, using NSCoder objects to bring the objects in to memory.
If you want to have a view controller based on a particular NIB, you can then override the default init method and init it based on the NIB for that view controller. For example:
#implementation MyViewController
-(id) init {
if (self = [super initWithNibName:#"MyViewController" bundle:nil]) {
//other setup stuff
}
return self;
}
And when you want to display the MyViewController, you would simply call something like this:
- (void) showMyViewController {
MyViewController *viewController = [[[MyViewController alloc] init] autorelease];
[self presentModalViewController:viewController animated:YES];
}
Now, if you want to create your view manually instead of in Interface Builder, you don't have to change your -showMyViewController method at all. Get rid of your -init override, and instead override the -loadView method of your MyViewController to create it programmatically:
- (void) loadView {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(320,460)];
self.view = view;
[view release];
//Create a button
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[myButton addTarget:self action:#selector(pressedButton) forControlEvents:UIControlEventTouchUpInside];
[myButton setTitle:#"Push Me!" forState:UIControlStateNormal];
myButton.frame = CGRectMake(100,230,80,44);
[self.view addSubview:myButton];
}
This example shows how to create the view and add a button to it. If you want to keep a reference to it, declare it the same way you would if you were using a NIB (without the IBOutlet/IBActions) and use self when assigning it. For example, your header might look like this:
#interface MyViewController : UIViewController {
UIButton *myButton;
}
- (void) pressedButton;
#property (nonatomic, retain) UIButton *myButton;
#end
And your class:
#implementation MyViewController
#synthesize myButton;
- (void) loadView {
//Create the view as above
self.myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[myButton addTarget:self action:#selector(pressedButton) forControlEvents:UIControlEventTouchUpInside];
[myButton setTitle:#"Push Me!" forState:UIControlStateNormal];
myButton.frame = CGRectMake(100,230,80,44);
[self.view addSubview:myButton];
}
- (void) pressedButton {
//Do something interesting here
[[[[UIAlertView alloc] initWithTitle:#"Button Pressed" message:#"You totally just pressed the button" delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK",nil] autorelease] show];
}
- (void) dealloc {
[myButton release];
[super dealloc];
}
I had the same issue a couple of months ago when I wanted to do all the iPhone development inside Emacs. To make a long story short: I'm not developing for the iPhone anymore :)
I'd still suggest you to check my question and some helpful answers here.
I typically don't use Interface builder too much for iPhone development. Usually I will create a view controller in code like this
MyUIViewControllerSubclass *controller = [[MyUIViewControllerSubclass alloc] initWithNibName:nil bundle:nil];
controller.someProperty = myModel;
[self presentModalViewController:controller];
[controller release];
Or something along those lines. Typically I create a subclass of UIViewController and that's where I layout my views and such. The views are subclasses of UIView (either things Apple provides like UIButton etc, or something I've created myself). If you read up on both UIViewController and UIView you should get a pretty good idea of how it works.