When do views get created? - objective-c

I apologize in advance for the n00b question. I am just getting started w/ iOS!
I am trying to push a webViewController onto a navigation controller.
mudWebViewController *webViewController = [[mudWebViewController alloc] initWithNibName:nil bundle:nil];
[[webViewController webView] setDelegate:webViewController];
[[self navigationController] pushViewController:webViewController animated:YES];
But this doesn't seem to work, as I don't see any of the logs in the delegate messages.
If I set the delegate in the viewDidLoad: method, it works fine.
I guess the webView doesn't actually exist at that point, but why? If I initialize the controller, shouldn't the webView be initialized too?
Is viewDidLoad: the right place to be setting up this stuff?

initWithNibName should be not nil, since you obviously are using a nib file to build the view, else you have to create the view in code, which you don't
mudWebViewController *webViewController = [[mudWebViewController alloc] initWithNibName:#"webViewController" bundle:nil];
[[self navigationController] pushViewController:webViewController animated:YES];
Also any delegates should be set either from the Interface builder or from the view itself in the viewDidLoad delegate and not from the previous class, as the object might not been yet initialized in the code so it can fail to set the delegate properly.

Related

pushviewcontroller after uiwebview finishes its load

I am properly pushing viewController B from A using navigationController. However, I would like to do it once uiwebview from viewController B finishes its load and not immediately. I tried firstly init B and push A when load ends but with no success, controller is not viewed. How can it be done? thank you.
from controllerA,
self.controllerB = [[BViewController alloc] initWithNibName:#"BViewController" bundle:nil anUser:self.idUser aLang:self.lang];
//[[self navigationController] pushViewController:controllerB animated:NO]; working if pushed directly here
[self.controllerB view];
then, controllerB is initialized, viewDidLoad triggered and when webviewDidFinishLoad, B must be pushed now or viewed at front.
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
AViewController *theInstance = [[AViewController alloc] init];
[theInstance pushBcontroller]; }
on AViewController,
-(void)pushBcontroller{
[[self navigationController] pushViewController:self.controllerB animated:NO];
}
not working...
The line AViewController *theInstance = [[AViewController alloc] init]; creates a new instance of a AViewController. Since it's new it isn't part of the view controller hierarchy and is therefore not connected to the navigation controller.
Give your BViewController a reference to the previous controller and use that instead of creating a different one. Or, perhaps better, send a notification when loading is done that the original AViewController uses to know when to change the display.

Going back to first ViewController from second ViewController

I'm building an app that currently has 3 ViewControllers. One of them is used after a successful login so is not relevant in this question.
I'm using a mixture of Storyboards and building things programmatically when I find Storyboards do not give me the fine control that I need.
The first ViewController is built in my 'MainStoryboard'. It has a login form and an info button at the bottom. I link it up the my AppDelegate by doing the following inside didFinishLaunchingWithOptions:
ViewController *viewController = (ViewController *)self.window.rootViewController;
Because I wanted to force rendering of a UIWebView (another story) I create the second view programmatically. I do the following inside didFinishLaunchingWithOptions:
infoViewController = [[InfoViewController alloc] init];
[infoViewController view];
Inside both of my ViewControllers I setup a link to appDelegate as below:
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
I have an info button in my first ViewController that takes you to the infoViewController. It calls the following code when tapped:
appDelegate.infoViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:appDelegate.infoViewController animated:YES];
The above works just fine for me, flips over the screen and shows the InfoViewController.
On my InfoViewController I have a button that should take you back to the login page, I have tried all sorts to get this to work but it just crashes my app. Nothing seems to work. I have tried the following:
appDelegate.viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:appDelegate.viewController animated:YES];
and
[self.navigationController popToRootViewControllerAnimated:YES];
and
[self.navigationController popViewControllerAnimated:YES];
and
[self.navigationController popToViewController:appDelegate.viewController animated:YES];
I suspect the last 3 might be more to do with when you have a navigation view controller and you want to go back to the root? I'm not sure, but either way it does not work. I had this working using storyboards previously so I'm sure it ought to be easy! As mentioned I switched to making the infoViewController programmatically so that I could force the UIWebView to render before the view appeared.
Any help much appreciated.
You can do with:
[self dismissModalViewControllerAnimated:YES];
You should use this.
[self dismissModalViewControllerAnimated:YES];
You should use a main controller for switching between your other view controllers. Change the view of your root controller to one of your other view controllers (apply animations as usual if needed). Hold a pointer to your root controller in your other view controllers and call self.rootController.view = <desired_controller_instance>.view
I think the way you're presenting your InfoViewController is wrong. Do it the following way:
In your ViewController, create an action for the info button.:
- (IBAction)infoButtonTapped:(id)sender
{
InfoViewController *infoViewController = [[InfoViewController alloc] init];
infoViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:infoViewController animated:YES];
}
And in your InfoViewController, in the action of your button that should take you back write this:
- (void)takeBackToViewController
{
[self dismissModalViewControllerAnimated:YES];
}
Hope it works.
Also in presented controller you can use this
if(self.parentViewController)
[self.parentViewController dismissModalViewControllerAnimated:YES];
else
[self.presentingViewController dismissModalViewControllerAnimated:YES];
To dissmiss current controller.

Image not being set in method

I have a class with a viewDidLoad method and an artworkInfo method as follows:
-(void)viewDidLoad {
mainDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
[super viewDidLoad];
}
-(void)artworkInfo:(NSNumber *)pos{
mainDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
[self.image setImage:(UIImage *)[[mainDelegate.mapAnnotations objectAtIndex:0]image]];
}
the mainDelegate thing is to gain access to the appDelegate where an array is stored, but anyway, with the "[self.image setImage...]" command where it is, the image on the app does not appear, but when I copy that exact line of code into the viewDidLoad method, it shows up like it should. I know that the artworkInfo method is being called because I debugged it and it goes through, so I can't figure out why the command would not be doing anything it's current method while it will in the viewDidLoad...?
Also, here is where the method is called and this new view is loaded from another class:
infoPage *info = [[infoPage alloc] initWithNibName:#"infoPage" bundle:nil];
info.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:info animated:YES];
infoPage *myInfoPage = [[infoPage alloc] init];
[myInfoPage artworkInfo:position];
[info release];
OH, I see the problem. You're instantiating 2 different infoPage classes.
Change this:
infoPage *info = [[infoPage alloc] initWithNibName:#"infoPage" bundle:nil];
info.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:info animated:YES];
infoPage *myInfoPage = [[infoPage alloc] init];
[myInfoPage artworkInfo:position];
[info release];
to this:
infoPage *info = [[infoPage alloc] initWithNibName:#"infoPage" bundle:nil];
info.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:info animated:YES];
[info artworkInfo:position];
[info release];
Ok detailed answer. In order to understand why this image is not displaying properly you have to first look at how Runloops work in Objective C.
While viewDidLoad is the method that is called when a view is loaded and it is technically also called before a view is displayed and it's view objects initialized. Since presentModalViewController is an animation there is actually some threading going on in the works.
viewDidLoad gets called before the animation is created for the presentModalView. This initializes your objects. However, due to some of the inner workings of UI Kit some processes are loaded off into a thread. When they complete they run callback methods on the main UI thread.
Since presentModalViewController is a non-blocking method your artworkInfo method gets added to the mainRunLoop before the initializer form thread adds its callback methods to the main run loop. The best approach would be to have both a UIImage property of your viewController and a UIImageView.
set the value of UIImage by calling artworkInfo BEFORE the presentModalViewController method.
in your ViewDidLoad go ahead and set the value of your UIImageView
[self.imageView setImage:self.image];
Problem solved.
This seems pretty straight forward.
So you initialize your nib and try to call your method artwork before the nib is fully loaded. <-- This is not working for you.
Then you do additional initialization by overrider viewDidLoad per the doco where the nib is loaded <-- This is working for you
So the answer is, when you call setImage before your nib is loaded, then there is nothing to set the image to. When you call setImage in viewDidLoad your nib is loaded and then things should work just fine.
I hope this explains it a bit.

How to switch to another view

The following code should work, right?
ViewController2 *childView = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
[self.navigationController pushViewController:childView animated:YES];
[childView release];
It doesn't do anything though. There are no error messages. The view just doesn't get switched. viewDidLoad does not even execute inside ViewController2.
That code won't do anything if the view controller presenting it doesn't have a navigation controller, i.e. it isn't in a navigation controller stack. In that case, you'll be calling a method (pushViewController:animated:) on a nil object (self.navigationController) which does nothing. Thus, you can only use this this method if the "parent" view controller is in a UINavigationController stack.
Use this:
[self presentModalViewController:viewControllerNameHere animated:YES];

How is it possible to come back to the same page?

I am new at Objective C. I am just trying to build an iphone app. I have created some NIB file, and i have gone to other NIB file by creating an object and using this code:
scoreViewController *sviewController = [[scoreViewController alloc] initWithNibName:#"scoreViewController" bundle:nil];
self.scoreView = sviewController;
[sviewController release];
// Setup the animation
[self.navigationController pushViewController:self.scoreView animated:YES];
Now I want to come back to the same page. For this case I have done the same work, but it does not work when I add the previous page header file name.
mainViewController *mainviewController = [[mainViewController alloc] initWithNibName:#"mainViewController" bundle:nil];
self.mcoreView = mainviewController;
[mainviewController release];
// Setup the animation
[self.navigationController pushViewController:self.mcoreView animated:YES];
So, I will be most grateful if you were so nice to post your comment.
I am not 100% sure what you are asking, but I think you want to go back from the the second controller to the first. What you are doing here is instantiating a second instance of the first controller (so you now have 3 controllers), and pushing it onto the stack. Assuming I have this correct, then if you want to move back to the first controller you should be popping the second controller off the stack, not adding a 3rd:
//mainViewController *mainviewController = [[mainViewController alloc] initWithNibName:#"mainViewController" bundle:nil];
//self.mcoreView = mainviewController;
//[mainviewController release];
// Setup the animation
[self.navigationController popViewControllerAnimated:YES];