I have passed the NSMutableDictionary into the FirstClass using custom init method.
Second Class,
firstClass = [[FirstClass alloc] initWithFeedData:feedDictionary];
[self.navigationController pushViewController:firstClasss animated:YES];
FirstClass,
- (FirstClass *) initWithFeedData:(NSMutableDictionary *) dataDictionary {
{
NSLog(#"%#", dataDictionary);
[[NSBundle mainBundle] loadNibNamed:#"FirstClass" owner:self options:nil];
//[self viewDidLoad]; Without call, ViewDidLoad method doesn't call.
}
- (void) viewDidLoad {
[super viewDidLoad];
NSLOG(#"Inside View DidLoad"); // This method never calls.
}
In my viewDidLoad method doesn't called, if i call "[self viewDidLoad]" then only, viewDidLoad method works properly. I donno why viewDidLoad method doesn't call directly without calls in another method? Please Help me out.
Thanks.
If you're subclassing a UIViewController, which I assume you are since you're expecting viewDidLoad, then you should override its designated initialiser, initWithNibName:bundle: if you're using a XIB, in which case viewDidLoad will be called after the XIB loads. If you're not using a XIB, you should implement the loadView method to create your view, and viewDidLoad will be called after loadView finishes.
#Stephen is right, at the very least you need to rewrite your init statement to return self. However, it's much easier and more robust to declare a property on your view controller and pass objects in that manner.
FirstClass *firstClass = [[FirstClass alloc] initWithNibNamed:nil];
firstClass.feedDictionary = feedDictionary;
[self.navigationController pushViewController:firstClasss animated:YES];
[firstClass release];
Your viewDidLoad method will now be called and your feedDictionary will be sitting there, waiting for you.
Your init method is not correct. It should look something like this:
- (id) initWithFeedData:(NSMutableDictionary *) dataDictionary {
if (self = [super init]) {
// TODO: do initialisation stuff with dataDictionary
}
return self;
}
This assumes that FirstClass is derived from UIViewController.
As long as your NIB file has the same name as your class it should be loaded in automatically -- there's no need for the loadBundle: call. Here's what the documentation says about the nibName property:
If the value of this property is nil
and you did not override the loadView
method in your custom subclass, the
view controller looks for a nib file
whose name (without the .nib
extension) matches the name of your
view controller class.
Related
I was trying to push a viewcontroller B into navigation controller from A and then assigning some properties of B in A.
In this case, the assigning of properties was done and then viewDidLoad of viewcontroller A was executed.
Here, assigning properties in A should be done only after viewDidLoad of A has done.
For example,
[b.navController pushViewController:a animated:YES];
a.status = #"loaded";
Here, status was assigned first and then viewDidLoad of A was executed.
This happens only in iOS 7 whereas in iOS6 it works fine.
Can anyone please let me know where the problem is?
UPDATE: For me in some cases in iOS7, Push view is not working. How cna I debug and fix it?
Just access the viewcontroller.view (set any thing immediately after the alloc) property after the alloc init;
Which will loadview/viewdidload.
See Apple Documentation
In my experience, a UIViewController view is loaded lazily, no matter which iOS version you're working on. If you want to trigger a view load, and therefore its UIViewController viewDidLoad, you should access the view after the UIViewController is allocated. For example:
UIViewController *aViewController = [[CustomViewController alloc] init];
[aViewController view];
Make sure you don't code it as
aViewController.view
since that would generate a compiler warning.
So, in your case it would have to be something like this:
...
CustomViewController *a = [[CustomViewController alloc] init];
[b.navController pushViewController:a animated:YES];
[a view];
a.status = #"loaded";
Let me know if you have further problems with it.
You can know when a View Controller has been pushed onto the stack by implementing the UINavigationControllerDelegate and setting yourself as the delegate self.navigationController.delegate = self; then you will get this callback after every push
navigationController:didShowViewController:animated:
So you can check if the shown viewController is the one your interested in, then set your a.status.
I would suggest you call a delegate method once the view is loaded.
Set the delegate to be controller B.
and after viewDidLoad finishes (in controller A) call the delegate method. You can even pass parameters as you wish to the delegate.
Here's some example code:
Controller B:
a.delegate = self;
[b.navigationController pushViewController:a animated:YES];
Implement the delegate method:
- (void)controllerIsLoaded:(ControllerA *)controllerA status:(NSString *)status
{
a.status = status;
}
Controller A .h file:
#class ControllerA;
#protocol ControllerADelegate <NSObject>
- (void)controllerIsLoaded:(ControllerA *)controllerA status:(NSString *)status;
#end
#interface ControllerA : UIViewController
#property (nonatomic, weak) id <ControllerADelegate> delegate;
Controller A .m file:
- (void)viewDidLoad:(BOOL)animated
{
[super viewDidLoad:animated];
/* your viewDidLoad code here... */
if ([_delegate respondsToSelector:#selector(controllerIsLoaded:status)])
[_delegate controllerIsLoaded:self status:#"Loaded"];
}
Turn off animation for ios7, in my case its work
[b.navController pushViewController:a animated:NO];
a.status = #"loaded";
No documentation provides enough information to know exactly when viewDidLoad would be called.
UIViewController's documentation just says this
This method is called after the view controller has loaded its view hierarchy into memory
I would suggest that you create a custom initializer like this
- (id)initWithStatus:(NSString *)status {
}
But, if you are trying to use this variable to check if the viewController's view has 'loaded' or not, it may not be possible to do that because the pushViewController or presentViewController methods are not guaranteed to be synchronous.
Even in iOS 6, there was no explicit guarantee that the view would be loaded as soon as that method returned.
Please write the code in viewWillAppear method instead of viewDidLoad in next class i.e. where you are pushing the object to
-(void)viewWillAppear:(BOOL)animated
{
}
I'm understand of your question like this:
B *b = [[B alloc] init];
b.status = #"loaded";
[self.navigationController pushViewController:b animated:Yes];
If you want to pass a value from one controller to another means, you have to assign a value before using pushViewController method.
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.
What is the full sequence events in terms of how a view controller loaded into memory from init to viewDidLoad?
If you do something like:
TabControllerClass *cc = [[TabControllerClass alloc] initWithCustomData:something];
Can the class's viewDidLoad get invoked before reaching the end of the custom init method, 'initWithCustomData'?
- (id)initWithCustomData:(NSString *)something
{
if (self = [super init])
{
// A bunch of other initialization happens
}
// Would you reach here before 'viewDidLoad' is invoked?
return self;
}
where my TabControllerClass inherits from UITabBarController.
I assume not. I mean, how can any method be called before the controller is correctly allocated and initialized? However, you may find that your -[ControllerClass initWithCustomData] initializer isn't the designated initializer, which could explain why it isn't being called.
The App Delegate has an outlet property to the view controller, and the view controller is created in the nib.
Althoug the -viewDidLoad method of the view controller gets loaded, it seems that it designated initializer receives no call:
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
NSLog(#"iniwinib");
if (self = [super initWithNibName:nibName bundle:nibBundle]) {
// do stuff
}
return self;
}
I also tried with -init, but this also does not receive a call. No NSLog output. Is there another initializer that I must use in this case?
-initWithCoder: is the initializer in this case (because the object is being deserialized from the NIB), but the routine you actually want here is -awakeFromNib. That's what's called after all the objects in the NIB have been constructed and all the outlets have been wired.
Are you actually calling initWithNibName to create your ViewController somewhere in the code? If not then it will never get called, this method does not get called automatically you must call it to create your viewController from your nib. But you dont need to do call this method because you have already set the ViewController in the nib..
A view controller FooViewController needs to do some initialization when it's created (of itself, not of the managed view - before the view is even loaded).
I want to be able to create it in two ways:
Programmatically, possibly with some arguments:
FooViewController *fooViewController = [[[FooViewController alloc] initWithSomeData:data] autorelease];
[self.navigationController pushViewController:fooViewController animated:YES];
In Interface Builder.
For (1) I would write the initializers like this:
- (id)initWithSomeData:(Data *)data // designated initializer
{
if (self = [super initWithNibName:#"FooView" bundle:nil]) {
self.title = "Foo";
// perform initialization
}
return self;
}
- (id)init
{
return [self initWithSomeData:nilOrSomeDefaultValue];
}
// ... other initializers that call the designated initializer
(I hardcode the nib name since the controller always uses the same view configuration and because which view it uses doesn't concern the callers at all)
When created in Interface Builder, I would want the end result be the same as if the object was initialized with the parameterless init.
Now if I just do:
- (id)initWithCoder:(NSCoder *)decoder
{
return [self init];
}
The title, wantsFullScreenLayout and nibName properties which are set in the Inspector in Interface Builder would then be ignored, but that's OK. The nibName is hardcoded in init and title is set there in case the controller is instantiated programmatically anyways.
The problem is that parentViewController isn't set (the default initWithCoder: would set it based on the hierarchy of objects in the NIB).
How can I get the parent object from the nib? I would then change initWithCoder: to something like:
- (id)initWithCoder:(NSCoder *)decoder
{
if (self = [self init]) {
_parentViewController = [decoder parentObject];
}
return self;
}
Or should I be using some different approach to create controllers which can be instantiated both programmatically and in IB?
Don't, don't, don't try to make a viewcontroller that works with and without a nib. It will be a nightmare because nibloading uses some of the normal entry points and provides new ones, and it will be fragile with respect to OS revisions.
What you can do is it make the view controller always load from a nib, then give yourself a convenience initializer to go through the nib:
- (id) init {
return [[[self class] alloc] initWithNibNamed:#"MyNibName" bundle:nil];
}
Then you can reference it through other nibs the normal way, and just call the convenience init method when you don't want to explicitly deal with the nib.
Why not do init stuff in viewDidLoad - when creating outside of IB, you can set initial values with some other methods or properties after initialization, but before viewDidLoad is called.