UIViewController and UITableViewController, how to change self.view then back again? - objective-c

I dont want to add a sub view, but instead change the "self.view" to another view eg (A warning view) then after the user suppresses the warning I would like to switch back. When ever i try to switch back to the original view i just get a blank screen for reasons i cant understand.
Here is what i currently have in one of my UITableViewControllers
//Show warning view controller
self.warningViewControler = [[[WarningViewController alloc] init] autorelease];
self.view = self.warningViewController.view;
//Then later
self.view = self.tableView; //<< Dosnt work

If you want to change your view, and if the original view is defined/linked into XCode, you must retain it before changing self.view to another view. If not, the original view is released and using it back can cause bad things to happen.
Warning :
self.warningViewControler = [[[WarningViewController alloc] init] autorelease];
self.view = self.warningViewController.view
is a bad bad call. Because you autorelease the controller but you use its view. So you get a view retained with a released controller after some time. Retain the controller and release it yourself when its view is not needed anymore.

Here's the better way to do what I think you're trying to do:
WarningViewController *warningViewController = [[WarningViewController alloc] initWithNibName:#"theRightNiborNil" bundle:nil];
[self presentModalViewController:warningViewController animated:YES];
// or if you don't need to support iOS4 any more:
[self presentViewController:warningViewController animated:YES completion:nil]
// and if you aren't using ARC yet, then [warningViewController release];
Then in your WarningViewController you want some action that calls:
[self dismissModalViewControllerAnimated:YES];
// or again if this is iOS5..
[self dismissModalViewControllerAnimated:YES completion:nil];
Hope that helps.

Related

ViewDidLoad not being called with my custom UIViewController

I have created a custom UIViewController class that creates a ScrollView at runtime that it loads into the view. See code here in the constructor of my custom UIViewController.
initControl(id, canEdit);
_controllers = new NSMutableArray(0); //required to keep view controllers around
_scrollView = new UIScrollView();
_scrollView.BackgroundColor = UIColor.Green;
this.View = _scrollView;
ViewDidAppear and ViewWillAppear are called normally.
ViewDidLoad is not called which I am not sure why as the view is showing up on the screen just fine.
Any ideas?
The viewDidLoad method is being called when accessing self.view
Examples:
1)
- (id) init {
self = [super init];
if (self)
{
...
[self.view addSubview: self.toolbar];
}
}
2)
viewContrl = [[MyViewController alloc] init];
viewContrl.view = webTopView;
3)
viewContrl = [[MyViewController alloc] init];
[viewContrl.view addSubview: webTopView];
ViewDidLoad is called when you are allocating the view. So if you are allocating the view once & only adding every time using addSubview then it called first time only. If you want to called it every time when you are adding it, then you needs to allocate it every time. Also handle memory management by releasing the view before allocating it, if it is already allocated.
Another way is to create a method which contains the operations which you wants to perform & called it after addSubview.
It may solves your problem, if you have any doubt then feel free to ask me.

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.

Wrong 'presentingViewController'

In my MainViewController, I present another view controller through this:
MessageViewController *messageController = [[MessageViewController alloc]initWithNibName:nil bundle:nil];
[messageController setModalPresentationStyle:UIModalPresentationFullScreen];
[messageController setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentViewController:messageController animated:YES completion:nil];
[messageController release];
This will display the view controller correctly. However, when I try to go back to the presenting view controller, which in this case should be the MainViewController, this code doesn't work:
if ([self.presentingViewController isKindOfClass:[MainViewController class]])
[(MainViewController *)self.presentingViewController setCurrentViewTag:2];
[self dismissModalViewControllerAnimated:YES];
I removed the "if.." condition to force it in setting the current view tag. An error occurred telling me that the presenting view controller seems to be the UINavigationController:
[UINavigationController setCurrentViewTag:]: unrecognized selector sent to instance 0x8352a50
Can anyone tell me why is this happening? This code used to work before and I am not sure what changed to make it stop working properly.
EDIT
Here is the updated code:
ReaderController *readerController = [[ReaderController alloc]initWithNibName:nil bundle:nil];
[readerController loadWhichViewToShow:2];
[self setDefinesPresentationContext:YES];
[readerController setModalPresentationStyle:UIModalPresentationFullScreen];
[readerController setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentViewController:readerController animated:YES completion:nil];
[readerController release];
Calling [self presentViewController:messageController animated:YES completion:nil]; doesn't necessarily use the vc you call this on to present the other vc. By default it travels up the vc-hierarchy and presents the other vc on the root view controller. That's why in your case the presenting view controller is a UINavigationController.
If you want to force your MainViewController to be the presenting vc, you have call:
[self setDefinesPresentationContext:YES];
on your MainViewController before presenting the MessageViewController.
Edit: In case someone else reads this: definesPresentationContext seems to be bugged or the documentation is wrong. See the comments below and Cocoa Builder
copy of my answer from this question
from Programming iOS 6, by Matt Neuburg:
On the iPad, when the presented view controller’s modalPresentationStyle is UIModalPresentationCurrentContext, a decision has to be made as to what view controller should be the presented view controller’s presentingViewController. This will determine what view will be replaced by the presented view controller’s view. This decision involves another UIViewController property, definesPresentationContext (a BOOL). Starting with the view controller to which presentViewController:animated:completion: was sent, we walk up the chain of parent view controllers, looking for one whose definesPresentationContext property is YES. If we find one, that’s the one; it will be the presentingViewController, and its view will be replaced by the presented view controller’s view. If we don’t find one, things work as if the presented view controller’s modalPresentationStyle had been UIModalPresentationFullScreen.
TL;DR
1. set definesPresentationContext to true on the desired presentingViewController
2. set modalPresentationStyle to UIModalPresentationCurrentContext on the desired presentedViewController
If seems that you need to set three thing in iOS 11.
controller.modalPresentationStyle = UIModalPresentationCurrentContext;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
self.definesPresentationContext = YES;
[self presentViewController:controller animated:YES completion:nil];

When do views get created?

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.

Remove all settings from viewcontroller when dismissed

I got multiple viewcontrollers in my project. The first viewcontroller is called when the application starts and it presents a login screen. When the credentials are correct and the user logs in, the modalview is dismissed. and another viewcontroller is instantiated like this:
[self dismissModalViewControllerAnimated:NO];
Form *formcontroller = [[Form alloc] init];
[self presentModalViewController:formcontroller animated:YES];
When my other viewcontroller is presented the old one disappears. On the top of my secondviewcontroller i got an logout button, wich does exactly the same, so it dismisses the current viewcontroller and calls another like this:
-(IBAction)logOut:(id)sender{
[self dissmissModalViewControllerAnimated:NO];
}
And in my viewdiddisappear:
-(void)viewDidDisappear:(BOOL)animated{
Postform3ViewController *logincontroller = [[Postform3ViewController alloc] init];
[self presentModalViewController:logincontroller animated:YES];
}
The problem is:
When i push the logout button, and i return back to the logincontroller. The Credentials are still filled in. So my conclusion is that the first viewcontroller stays in memory. What am i doing wrong?
Edit:
I did find my own solution. I was profiling my application, and couldn't find any memory leaks. So i decided everything is released. Then i thought that i was able to set everything to empty myself. I did that in the viewDidAppear method like this:
-(void)viewDidAppear:(BOOL)animated {
gebruikersnaam.text = #"";
wachtwoord.text = #"";
[self.activeTextField resignFirstResponder];
[super viewDidAppear:animated];
}
Well first of all when you are using presentModalViewController and pushViewController the VC is retained so you should always release it after you have presented or pushed it.
Secondly in the third block of code it looks like you are creating a logincontroller but presenting a formcontroller. Perhaps you want to be presenting the VC you had just created:
[self presentModalViewController:logincontroller animated:animated];
Edit 0: For your code, in the first block, release like this:
Form *formcontroller = [[Form alloc] init];
[self presentModalViewController:formcontroller animated:YES];
...
[self dismissModalViewController:formcontroller animated:YES];
[formcontroller release];