Obj C - Present view controllers one after another - ios

It may be simple, but i'm scratching my head to find out the issue.
I'm presenting a UINavigationController and once it's dismissed I need to present another one which is a UITabBarController, when I do that I get below error
Warning: Attempt to present < MyTabBarViewController: 0xXXXX > on <
ParentViewController: 0XXX> whose view is not in the window hierarchy!
UINavigationController *nav = [self.storyboard instantiateViewControllerWithIdentifier:#"myWeb"];
MyWebViewController *webVC = (MyWebViewController *)nav.topViewController;
[self presentViewController:webVC animated:YES completion:nil];
I can see MyWebViewController is presented without any issue, once the previous one is dismissed, I try to present next one like below, I'm getting the above warning.
MyTabBarViewController *trController = [[MyTabBarViewController alloc] init];
[self presentViewController:trController animated:NO completion:nil];

You need to present MyTabBarViewController only when the MyWebViewController has finished dismissing,
try adding a delay like this:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
MyTabBarViewController *trController = [[MyTabBarViewController alloc] init];
[self presentViewController:trController animated:NO completion:nil];
});
if this works, you will need to get rid of that (in case you want to keep your code clean) and call a delegate method inside completion telling the parent that the MyTabBarViewController is ready to be presented.

Related

Issue while pushing ABNewPersonViewController

I am using AddressBookUI Framework for Adding contact, when I tried to pushing this view controller then cancel and done button not working properly, I don't want to present it
Here is my code
ABNewPersonViewController *abnpvc = [[ABNewPersonViewController alloc] init];
[abnpvc setNewPersonViewDelegate: self];
[self.navigationController pushViewController:abnpvc animated:YES];
I am also tried add as subview rather then pushing it but when I am adding as subview then it was not added
As per comment i have tried like
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:abnpvc];
[self presentViewController:navigation animated:YES completion:nil];
Can anyone help me out why properly not working ?
You can implement that too considering also the other answers and the deprecations to ABNewPersonViewController in iOS 9.
As per your remarks:
cancel and done button not working properly
They are working if you have included the ABNewPersonViewControllerDelegate on interface like this:
#interface ViewController () <ABNewPersonViewControllerDelegate>
Pushing the viewController on navigation stack like this:
ABNewPersonViewController *controller = [[ABNewPersonViewController alloc] init];
controller.newPersonViewDelegate = self;
[self.navigationController pushViewController:controller animated:YES];
And by conforming to the protocol by implementing this method:
- (void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(nullable ABRecordRef)person {
// Trick to go back to your view by popping it from the navigation stack when done or cancel button is pressed
[self.navigationController popViewControllerAnimated:YES];
}
The tricky line is to pop the newPersonController from the navigation stack when either Done or Cancel button are pressed.
Enjoy it
Why can't you just do it as the docs say?
It is recommended that you present a new-person view controller modally.
Use
ABNewPersonViewController *abnpvc = [[ABNewPersonViewController alloc] init];
[abnpvc setNewPersonViewDelegate: self];
[self presentViewController:abnpvc animated:YES completion:nil];
That should work fine.
Edit
On second thought, did you set your delegate correctly and do the implementations get called? I suspect they are not implemented or the delegate is not set correctly.
Apple guideline(IMPORTANT) :: New-person view controllers must be used with a navigation controller in order to function properly. It is recommended that you present a new-person view controller modally.
Add Delegate
#interface ViewController () <ABNewPersonViewControllerDelegate>
Pushing the viewController
ABNewPersonViewController *abnpvc = [[ABNewPersonViewController alloc] init];
[abnpvc setNewPersonViewDelegate: self];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:abnpvc];
[self presentModalViewController:navController animated:YES];
And Now Add Delegate Method
#pragma mark ABNewPersonViewControllerDelegate methods
- (void)newPersonViewController:(ABNewPersonViewController *)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
That will work fine.

when i use dismissviewcontrolleranimated , i got exc_bad_access

I got an error exc_bad_access,when i use dismissviewcontrolleranimated
the presentViewController code is:
TestViewController *testViewController=[[TestViewController alloc] init];
UINavigationController *nav=[[UINavigationController alloc] initWithRootViewController:testViewController];
[self presentViewController:nav animated:YES completion:^{
NSLog(#"presentViewController is finish");
}];
but,when i remove UINavigationController ,is error is disappear.
like this:
TestViewController *testViewController=[[TestViewController alloc] init];
[self presentViewController:testViewController animated:YES completion:^{
NSLog(#"presentViewController is finish");
}];
Thanks for help.
Present View Controller is presented over a "Root View Controller" not a UINavigationController.
You should present your VC from the Parent VC or Base VC like this
TestViewController *testViewController=[self.storyboard instantiateViewControllerWithIdentifier:#"storyboardIDofViewController"];//set the storyboard ID of the TestViewController in your storyboard by selecting attribute inspector after selecting the view controller.
[self presentViewController:testViewController animated:YES completion:^{
NSLog(#"presentViewController is finish");
}];
This is the correct way to present a VC from another VC.
UINavigationController have Push and Pull transitions and you are trying to apply Modal Transition to it.

Creating modal view from another modal view fails

In a view that was created modally, pressing a button causes the modal view to be dismissed and another modal view to load.
- (void)loadLanguageSelectionView {
[self dismissViewControllerAnimated:YES completion:nil];
UIViewController *languageSelectionController = [[LanguageSelectionViewController alloc] initWithNibName:nil bundle:nil];
[languageSelectionController setModalPresentationStyle:UIModalPresentationCustom];
[languageSelectionController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self presentViewController:languageSelectionController animated:YES completion:nil];
}
The following error is thrown when this code block executes:
DenkoStation[4259:73173] Warning: Attempt to present <LanguageSelectionViewController: 0x7b185430> on <ViewController: 0x79f52e50> whose view is not in the window hierarchy!
What surprises me is the fact that the code was running happily before I made some changes to my code as outlined here.
Where's the mistake?
Because you are trying to present a viewController on top of a viewController which is already dismissed and no longer in window hierarchy.
What you can try is, you can take the ParentViewController reference from current viewController and then you can present new viewController on ParentViewController Like This :
- (void)loadLanguageSelectionView {
UIViewController *parentController = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
UIViewController *languageSelectionController = [[LanguageSelectionViewController alloc] initWithNibName:nil bundle:nil];
[languageSelectionController setModalPresentationStyle:UIModalPresentationCustom];
[languageSelectionController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[parentController presentViewController:languageSelectionController animated:YES completion:nil];
}];
}

Muiltple Modal UIViewControllers | Dismiss Top Modal UIViewController Only

My UIViewController stack looks as follows:
+------ UIViewController_C (presented)
+---- UIViewController_B (presented)
+-- UIViewController_A (pushed)
When I call -dismissViewController:animated on UIViewController_C, UINavigationController dismisses both UIViewController_C and UIViewController_B together, as per the docs with animation on _C, and none on _B.
What is the most compliant way to dismiss _C only?
try as below
after pushing to UIViewController_A present UIViewController_B as below code.
UIViewController_B *bbp=[[UIViewController_B alloc]initWithNibName:#"UIViewController_B" bundle:nil];
UINavigationController *passcodeNavigationController = [[UINavigationController alloc] initWithRootViewController:bbp];
passcodeNavigationController.navigationBar.hidden=YES;
[self.navigationController presentModalViewController:passcodeNavigationController animated:YES];
[passcodeNavigationController release];
now from UIViewController_B try to present in UIViewController_C as below code.
UIViewController_C *bbp=[[UIViewController_C alloc]initWithNibName:#"UIViewController_C" bundle:nil];
UINavigationController *passcodeNavigationController = [[UINavigationController alloc] initWithRootViewController:bbp];
passcodeNavigationController.navigationBar.hidden=YES;
[self.navigationController presentModalViewController:passcodeNavigationController animated:YES];
[passcodeNavigationController release];
last and final thing on every back button of view controller write below line of code.
[self dismissModalViewControllerAnimated:YES];
if you want more help than comment bellow.
One Solution:
UIViewControllers presented modally are not necessarily deallocated on -dismissViewController:animated.
This means that by passing a reference to UIViewController_A through _B to _C, you can call -presentViewController:animated and -dismissViewController:animated for the respective UIViewControllers via UIViewController_A.
Code:
1. UIViewController_B
- (void) showUIViewController_C {
[self dismissViewControllerAnimated:TRUE completion:^{
UIViewController_C *controller_C = [[UIViewController_C alloc] init];
controller_C.parentController = self;
[self.parentController controller_C animated:TRUE completion:nil];
}];
}
2. UIViewController_C
- (void) dismissUIViewController_C {
[self dismissViewControllerAnimated:TRUE completion:^{
[self.parentController.parentController presentViewController:self.parentController animated:TRUE completion:nil];
}];
}
Where I am using *parentController as the naming convention for whatever class your previous UIViewController on the stack may be.
It dips back to UIViewController_A briefly because I am calling -dismiss and -present in the completion block, though that actually looks rather fun.

View Controller Presentation Warning - Presenting two at the same time

I am getting this warning when I try to present a second VC modally.
Warning: Attempt to present <RCTAddCardViewController: 0x1f5b21e0> on <IRSlidingSplitViewController: 0x1f538140> while a presentation is in progress!
Here is how I'm doing it:
UIViewController *pvc = [self presentingViewController];
[self dismissViewControllerAnimated:YES completion:^{
RCTAddCardViewController *vc = [[RCTAddCardViewController alloc] initWithNibName:nil bundle:nil];
[pvc presentViewController:vc animated:YES completion:nil];
}];
I shouldn't be getting the error bc it's being presented inside the completion handler of the first VC's dismissal. Anyone know a way to get this to go away?
Since you're calling -dismissViewControllerAnimated: on self, if you were also presenting a view controller by self, that view controller would be dismissed (so pvc would still be presenting self). If that's not the issue, I guess it only counts the presentation complete after the completion block has returned.
One workaround would be to create a -myPresentViewController: method, and use use
[self performSelector:#selector(presentViewController:) withObject:vc afterDelay:0.001]
inside the block

Resources