ModalView on the top of UITabBarController during app launch - ios

I'm a bit lost trying to figure it out...
I have a tab bar based app with login screen at the start. Login screen should be done as Modal View Controller BEFORE tab bar controller appears.
The problem is that I can present it only in viewDidAppear: method of TabBarController. And user can see for half a second content of the UITabBarController. I've tried to move call to viewDidLoad: or viewWillAppear: but it logs an error in console: "whose view is not in the window hierarchy!". As far as I can understand you can only add ModalViewController when all child UIViewControllers of UITabBarController are loaded, ad that happens in viewDidAppear: delegate method.
Do you have any solution how to show login screen without showing TabBarController before?
I've tried 2 ways of displaying ModalViewController, both of them work in viewDidAppear: only
XIB file with login view and using presentViewController: code
self.loginController = [[LoginViewController alloc] init];
[self presentViewController:self.loginController animated:NO completion:nil];
Storyboard, modal segue and calling it from the code:
[self performSegueWithIdentifier:#"loginScreen" sender:self];

Instead of a modal, you might consider pushing the login screen onto a navigation stack. Inside viewWillAppear: you can just instantiate your login viewController and push it. You could also do it in viewDidLoad if you'd like.
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.navigationController pushViewController:yourInstantiatedLoginViewController animated:NO];
}

Related

Modal Presentation Forcing Navigation Controller to Pop to Root

I am having a strange problem that I can't seem to find the cause for.
When attempting to present a modal view controller on a navigation controller the navigation controller is popping all of my view controllers underneath when the modal is dismissed.
So after pushing a few view controllers and presenting a modal on the topViewController, I end up back at the rootViewController when the modal is dismissed.
Anyone had this happen to them lately, I can't seem to find the reasoning for why this is happening?
This answer is for #rshev:
It was actually a user error. Here's what was happening: I had a view controller with a manually added navigationController on top of it (as a subview/child VC). The nav controller then had 3 VCs in its stack. The third (and visible) VC was presenting an image picker controller. When the image picker was dismissed, I momentarily saw my third VC , then it quickly popped back to the 1st, discarding the other two VC's from memory.
So what went wrong? What I didn't realize is that viewDidAppear (and viewWillAppear) was being called on my content view controller (the one with nav controller for its subview). This content VC was actually setting its navigation controller (and adding it as a subview) on viewDidAppear, thus covering up the original nav controller.
To solve it, I just added a static boolean to determine when the first VC FIRST appears, like so:
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
static BOOL firstAppearance = YES;
if (firstAppearance)
{
firstAppearance = NO;
UINavigationController *navController = [self.storyboard instantiateViewControllerWithIdentifier:#"NavigationController"];
[navController.view setFrame:self.view.bounds];
[self.view addSubview:navController.view];
[self addChildViewController:navController];
[navController didMoveToParentViewController:self];
}
}
Hope that helps.

Going from a Storyboard to Nib and back again

Ok, I'm still pretty new; so, please bear with me.
I'm creating a custom app for a friend that displays a list of work orders in a table view. Clicking on a work order brings them to a detail view. In the detail view, there is a button that uses a push to present another screen called completion view. From the completion view, they click a button that uses the following code to present a nib for signature capture.
SigScreenViewController *sigScreenViewController=[[SigScreenViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil];
[self presentViewController:sigScreenViewController animated:YES completion:nil];
The signature screen uses: https://github.com/jcmontiel/SignatureViewExample for capturing the signature and does it well. I have a button that completes the transaction and sends it back to the table view list.
My problem is that I cannot create a button that will return me to the completion view in the storyboard.
I've tried the following in a button:
[self dismissViewControllerAnimated:YES completion:nil];
or
[self.navigationController popViewControllerAnimated:YES];
I'm open for any suggestions on how I can do it.
Thanks in advance!
Have you tried having the UIViewControllers embedded in a navigation controller ?
Are you pushing from a UIViewController in UIStoryboard to a NIB file?
If so check out this sample project that pushes from storyboard to a NIB:
// in a navigation controller
// to load/push to new controller use this code
// this will be next screen
DetailsViewController *detailsViewController = [[DetailsViewController alloc ]init];
[self.navigationController pushViewController:detailsViewController animated:YES];
// to go back or pop controller use this
// now it will send back to parent screen
[self.navigationController popViewControllerAnimated:YES];

Adding child view to UITabBarController not call viewWillAppear

I have tab bar based application (iOS 7.1 SDK). When user start app at first time, I want show some login screen. I decided to use view controller containment (this is called in first view controller of tab bar controller):
LoginViewController *vc = [LoginViewController new];
[self.tabBarController addChildViewController:vc];
[vc didMoveToParentViewController:self.tabBarController];
[self.tabBarController.view addSubview:vc.view];
But there are some problems. View is normally visible, but in LoginViewController viewWillAppear and viewDidAppear are never called. I try to use this piece of code in all view lifecycle methods (viewDidLoad, viewWillAppear, viewDidAppear), but with no luck. I know there are some other ways to achieve what i'm trying to do. For example add child controller to first view controller of tab bar controller and hide tab bar, which works great and viewWillAppear and viewDidAppear are normally called. But because of this I get even more curious - why adding child view controller to tab bar controller don't work as expected?
You need to present or push the viewcontroller in order for the methods to get called. Just adding the view as a subview will not work.
In your case, you can explicitly call the viewWillAppear, viewDidAppear methods.
LoginViewController *vc = [LoginViewController new];
[self.tabBarController addChildViewController:vc];
[vc didMoveToParentViewController:self.tabBarController];
[self.tabBarController.view addSubview:vc.view];
[vc viewWillAppear];
[vc viewDidAppear];
It's working!
dispatch_async(dispatch_get_main_queue(), ^{
[self.tabBarController setSelectedIndex:0];
[self.tabBarController setSelectedIndex:1];
[self.tabBarController setSelectedIndex:0];
});

Getting black screen when trying to remove ViewController from display in iOS

I have an iOS application using storyboards where I display a view controller that I create from an .xib file to the user. This view controller accepts some user input, but I then have to dismiss it and return to the main application. I am able to display the view controller, which also has a button that calls a method to dismiss the view controller. My problem is that after the user presses the button to go back to the main application, the entire screen goes black. Here is my code for the button from the .xib view controller that is trying to remove itself from the display:
- (IBAction)myButtonAction:(id)sender {
[self.view removeFromSuperview];
}
Here is the code from my main application's view controller which calls the .xib view Controller in the first place:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
_nextView = [[NextLandscapeViewController alloc] initWithNibName:#"NextLandscapeViewController" bundle:nil];
[_nextView setDelegate:(id)self];
NextNavigationController *navigationController = [[NextNavigationController alloc] initWithRootViewController:_nextView];
[self presentViewController:navigationController animated:YES completion:nil];
}
NextNavigationController is a subclass of UINavigationController which I do for the purpose of loading _nextView in landscape mode instead of portrait mode. This part is working fine. My concern now is dismissing this viewController after the user is finished working with it, and return back to the calling view controller in the main application.
Is there any reason why my screen is black? How I can resolve this issue?
Don't use removeFromSuperview, use [self dismissViewControllerAnimated:YES completion:nil]; Just like you use a pop to undo a push, you use dismissViewController to undo a presentViewController. The reason you get a black screen is because presenting a view controller removes the view of the presenting view controller from the window's hierarchy. So, when you remove the view from the superview, there's nothing underneath but the window.

ViewDidAppear not called in main view when modal view is presented over a popover

I'm trying to use a popover as an intermediary menu between my main view and a modal view controller. I can successfully present the Modal view controller from the popover by using the following code:
UIStoryboard *storyboardiPad = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
cbwEditControlPanel *editCP = [storyboardiPad instantiateViewControllerWithIdentifier:#"EditCP"];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:editCP];
[nav setToolbarHidden:NO];
[nav setModalPresentationStyle:UIModalPresentationFullScreen];
[nav setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentViewController:nav animated:YES completion:nil];
self.modalInPopover = NO;
The problem I'm running into is that when the EditCP modal view controller is dismissed, the main view controller never updates. I have a pagecontroller on the main view that should be updated to reflect the number of pages as set in the EditCP modal view controller, but for some reason the modal view controller being called from the popover prevents the main view controller from updating the pagecontroller. I've even tried calling the main view's "View Will Appear" method from the popover or modal view when they are dismissed, but even if the 'viewWillAppear' method is called the pageController will not update!
Any ideas what is preventing the pageController from updating? I even passed a reference to the pagecontroller to the modal view and tried to update it there, but it seems that from the time the popover is presented until it is dismissed, I cannot update the number of pages on the PageController.
Thank you!
So this is an old question but I also came across a similar problem recently when using a popover. My solution was to use an unwind segue to trigger my parent view to perform some action. In my case my parent view contains contact information and the popover contains a list of cites. All I wanted to do was to have the parent view update with the new city once the user selected it from the popover. So in my parent view I create my unwind function as follows:
In the .h:
- (IBAction)unwindToContactTVC:(UIStoryboardSegue *)unwindSegue;
In the .m:
- (IBAction)unwindToContactTVC:(UIStoryboardSegue *)unwindSegue
{
[self updateTableForOffice];
}
In the above .m file is where you would have the logic to do whatever it is you want to in the parent view. To connect this unwind segue go to the child view in the storyboard and control drag from the view icon to the exit icon. You should see a pop up with the name of your unwind segue.
Finally, give that unwind segue a name and then in the child controller in the viewWillDisappear() function call the segue as follows:
- (void)viewWillDisappear:(BOOL)animated
{
[self performSegueWithIdentifier:#"unwind-to-contact-tvc" sender:self];
}
I hope that helps. If someone has a better solution let me know.
Well, I half solved the problem. The only way to get an update function when the popover disappeared was to stop using Storyboards and programmatically present the popover, using the main view as the delegate. I then was able to update correctly inside the popoverControllerDidDismissPopover method.
However, I am still interested in finding a way to update the pageControl when the modal is dismissed, before the popover is dismissed.

Resources