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)
Related
In my UIViewController named MainViewController, I have a reference to another UIViewController named SubViewController. It is defined as follows:
#class SubViewController;
#interface MainViewController : UIViewController <UIScrollViewDelegate> {
SubViewController * _subViewController;
}
In the initWithNibName:bundle: method of my MainViewController, I initialize my SubViewController as follows:
#pragma mark - Init
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil; {
if((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])){
_subViewController = [[SubViewController alloc] initWithNibName:#"SubViewController" bundle:nil[;
// Forces the view to load, in an attempt to speed up the adding of the subview.
UIView * view = _subViewController.view;
view.alpha = 1.0f;
}
return self;
}
The viewDidLoad method of the SubViewController does get called, and everything seems to be loaded, but when I add the SubViewController as a subview:
- (IBAction)showButtonPressed:(UIButton *)aButton; {
[self.view addSubview:_subViewController.view];
}
The app slows down for a couple of seconds, and then the subview is added and everything is fine. The strange thing is, when I remove the subview and try to re-add it again, there is no delay!
I assume the issue is a loading one, but I can't find any documentation on how to solve this.
Can anyone explain what is causing this slow down? Thanks!
your code its not complete !!
i try to take your code and make new project -ARC- and its fain to me no delay at all
try to use Instruments to find whats happen
I never had issues like that. since you are saying if you don't load the second view it works faster. check to see what is in the viewWillAppear and viewDidAppear for the secondViewController
I have a UIViewController called LaunchController that is launched in my iPhone app when the app first opens:
#interface LaunchController : UIViewController<UINavigationControllerDelegate, UIImagePickerControllerDelegate>
Then, when a button is clicked, I push another view controller:
MainController *c = [[MainController alloc] initWithImage:image];
[self presentModalViewController:c animated:NO];
MainController has the following constructor, which I use:
- (id)initWithImage:(UIImage *)img
{
self = [super init];
if (self) {
image = img;
NSLog(#"inited the image");
}
return self;
}
and then it has a viewDidLoad method as follows:
- (void)viewDidLoad
{
NSLog(#"calling view did load");
[super viewDidLoad];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[self.view addSubview:imageView];
NSLog(#"displaying main controller");
}
When the program runs, I see that the constructor for MainController is called (due to the output of NSLog), however viewDidLoad never gets called, even though I am calling presentModalViewController. Why is this? Why isn't viewDidLoad being called?
I think it is something as followings. When you need the property of view inside UIViewController, it will be loaded with lazy manner.
- (UIView *)view
{
if (_view == nil) {
[self loadView]; //< or, the view is loaded from xib, or something else.
[self viewDidLoad];
}
return _view;
}
After the view initialized, it will call viewDidLoad to inform the UIViewController.
You aren't loading your view controller from a xib file, and from comments you don't have anything in loadView (which is where you would create your view controller's view if you were not using a xib file).
Therefore, your view isn't being loaded, so viewDidLoad is never called.
Typically you would use initWithNibName: to initialise a new view controller, and then set the image after it (so expose the image as a property).
viewDidLoad will be called as soon as your controller's view property is accessed, that is when you display it for the first time or request it (e.g. have some code that calls c.view.
The reason viewDidLoad is not being called is because you aren't loading a view.
In your init method:
self = [super init];
means that you are just creating a naked view from scratch. not loading one from a nib.
try this instead:
self = [super initWithNibName:nil bundle:nil];
If you have a xib or nib file with the same name as the view controller class it should find if. Otherwise, you can just give a nibName that works.
UPDATE:
If you are not using nib files, then the appropriate method is NOT viewDidLoad. You have to implement loadView instead of viewDidLoad.
In your specific case, just put everything that is currently in viewDidLoad into loadView.
I am using a delegate to store data for my app. I have a tabviewcontroller with a navigationviewcontroller as the first view controller. When i set the delegate using
delegate = [[UIApplication sharedApplication] delegate];
the delegate is null outside of the init method.
It however works fine when places in viewDidLoad. Any ideas why this could be?
UPDATE
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
delegate = [[UIApplication sharedApplication] delegate];
}
return self;
}
Is this view controller in your MainWindow.xib file (or whatever the main .xib in your project is called)? If so, the app delegate is likely also created when that file is loaded, and the app delegate probably is nil at time your view controller is created. If your app delegate has a reference to this view controller, have it set itself as the view controller's delegate in -applicationDidFinishLoadin:withOptions:, or just connect the app delegate to the view controller's -delegate outlet in the .xib file.
You shouldn't use -init method. Sometimes it's not being called. Use theese methods for additional initialization:
- (void)viewDidLoad {
[super viewDidLoad];
// do something
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// do something
}
The nib file was calling the initWithCoder method, not init.
I have a tab based application I am working on.
I have a view controller named DetailsView.m, with an accompanying nib file called DetailsView.xib. This has a couple of UILabels in, which are linked using IBOutlet to DetailsView.m view controller. When I load this view controller/view using the tab bar controller, it works fine and the UILabels are populated dynamically.
Now I want to load this entire view inside a UIScrollView instead so I can fit more content in.
So I created another view controller called DetailsHolder.m with a nib file called DetailsHolder.xib, and assigned this to the tab bar controller.
I wrote this code below to load the first view (DetailsView) into the UIScrollView in the second view (DetailsHolder). I wrote it in the viewDidLoad method of DetailsHolder:
DetailsView* detailsView = [[DetailsView alloc] initWithNibName:#"DetailsView" bundle: nil];
CGRect rect = detailsView.view.frame;
CGSize size = rect.size;
[scrollView addSubview: detailsView.view];
scrollView.contentSize = CGSizeMake(320, size.height);
This correctly loads the sub view into the UIScrollView, however, the labels inside DetailsView no longer do anything. When I put an NSLog inside viewDidLoad of DetailsView - it never logs anything. It's as if I've loaded the nib ok, but its no longer associated with the view controller anymore. What am I missing here? I'm a bit of a newbie in obj C/iOS (but have many years Actionscript/Javascript knowledge.
Thanks in advance,
Rich
Edit: Contents of DetailsView as requested:
DetailsView.h:
#import <UIKit/UIKit.h>
#import "AppModel.h"
#interface DetailsView : UIViewController {
IBOutlet UITextView* textView;
IBOutlet UIImageView* imageView;
}
#end
DetailsView.m
#import "DetailsView.h"
#implementation DetailsView
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewWillAppear:(BOOL)animated
{
AppModel* model = [AppModel sharedInstance];
[model loadData];
int selectedLocation = [model getSelectedLocation];
NSArray *locations = [model getLocations];
NSArray *data = [locations objectAtIndex:selectedLocation];
textView.text = [data objectAtIndex: 0];
UIImage *theImage = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[data objectAtIndex: 4] ofType:#"jpg"]];
imageView.image = theImage;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Essentially all its doing is grabbing selectedLocation (int) from a singleton (which is my model), then grabbing an array from the model, and then trying to insert an image and some text into my view. In my nib file, i have a UIImageView and a UITextView, which I have linked to the two IBOutlets declared in DetailsView.h
When you use the view controller like this, many events will not occur in the view controller, e.g. viewWillAppear, viewWillDisappear and device rotation event. My best guess that you did some initialisation in some of those event methods. Posting your code for DetailsView would make it easier to find the problem.
I have a uiviewcontroller with two properties: trackName and playerObject. PlayerObject also has a trackName property. I call this uiviewcontroller from my main uiviewController with this code:
SecondaryViewController *nextViewController = [[SecondaryViewController alloc] initWithNibName:#"SecondaryViewController" bundle:nil];
NSString *trackName = #"a track";
nextViewController.trackName = trackName;
[self.navigationController pushViewController:nextViewController animated:YES];
[nextViewController release];
In SecondaryViewController I override the initwithnibname method to set the trackName of the playerObject. I do this with this code:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
playerObject.trackName = trackName;
}
playerObject.trackName = trackName;
return self;
}
Finally my playerObject has all of the view data the SecondaryViewController will need. It looks like:
- (void)awakeFromNib{
NSString *s = trackName;
//more code relevant to the the view controller
}
When I debug, the trackName string in the playerObject is nil. I assume I'm doing something wrong. How can I have this value populated with the trackName I originally passed in the main uiview controller?
It seems like when you are initing the viewController the playerObject variable has not yet been set, could this be possible?
This can sometimes happen when you override initWithNibName:bundle:.
Instead use viewDidLoad to do setup. Apple guarantees all required setup is performed before this method is called (not the case with initWithNibName:bundle:).