I'm trying to present a custom UIViewController with one method and dismiss the same UIViewController from another method.
The method being used to present the controller:
-(void)presentViewController {
self.customView = [[UIViewController alloc] init];
[self.customView setModalPresentationStyle: UIModalPresentationOverFullScreen];
[self presentViewController:self.customView animated:YES completion:nil];
}
The method being used to dismiss the controller:
-(void)dismissViewController {
[self.customView dismissViewControllerAnimated:YES completion:nil];
}
When creating a button within my customView, that calls dismissViewController, nothing happens. I know the method is being called because the completion: tag is working, yet nothing happens visually. No errors are being printed to console either.
Maybe I'm doing the whole thing wrong but any help is appreciated! Just trying to learn.
Related
please help to understand the difficult situation.
I realized the Pop Up Window, the way has been described here
Then, in this window, I decided to implement a sample photo from the library, but when you open a new controller may receive the following warning:
Presenting view controllers on detached view controllers is discouraged <PopUpViewController: 0x7fbb405f4e90>.
The sample photo is implemented as follows:
picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = NO;
[picker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
[self presentViewController:picker animated:YES completion:nil];
try this:
[self.view.window.rootViewController presentViewController:picker animated:YES completion:nil];
I think you are presenting your picker in your viewDidAppear method.
If this is so, then that is the reason for the warning...
Please write another method that will present our picker and then perform it with delay.
[self performSelector:#selector(yourMethod)
withObject:nil afterDelay:0.0];
This will let your presentingController load completely before it presents another one.
I hope this helps..
EDIT
The problem is, you are presenting the picker, much before your action sheet is dismissed
EDIT 2
Also instead of actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex, use this method for getting clicked Index -
- actionSheet:didDismissWithButtonIndex:
Perhaps you need to add your popup window as a child controller using addChildController to the controller you show it from so that it is not detached from a view hierarchy?
Also you could try: Another option:
[self.parentViewController presentViewController:picker animated:YES completion:nil];
I noticed this on another thread as a solution. Warning :-Presenting view controllers on detached view controllers is discouraged
In your case, parentViewController may well be nil.
Edit After Seeing Code:
After looking at the code, the problem seems to be as follows:
1) The popup mechanism is using an instance of a UIViewController to create a layout, but you are not actually using the view controller at all. The popup mechanism (showInView:withImage:withMessage:animated:) is extracting the view from the controller and adding it into the view hierarchy of the controller asking for the popup. So using code from this popup controller instance which calls [self presentViewController...] is presenting a modal controller from a controller which is not actually being used. This is where the error is coming from I believe. You need to do all alerts and modal presentations from the original controller OR pass in the controller to use.
2) The original article mentions that because only the container view of the controller is used, you need to keep a strong reference to it when you create it. So you should have:
self.popViewController = [[PopUpViewController alloc] initWithNibName:#"PopUpViewController" bundle:nil];
Solution:
I would extend the showInView... method to pass in the controller which owns the view the popup is being spliced into. Then use this controller to present any modal controllers. So change:
- (void)showInView:(UIView *)aView withImage:(UIImage *)image withMessage:(NSString *)message animated:(BOOL)animated
to
- (void)showInController:(UIViewController *)aController inView:(UIView *)aView withImage:(UIImage *)image withMessage:(NSString *)message animated:(BOOL)animated
Store the controller reference passed in a property in your PopUpViewController class then use this property to call presentViewController...
I have a HomeView and a HomeDropDownView.
HomeDropDownView is shown as a drop-down view over the HomeView.
HomeView is a delegate of HomeDropDownView.
When I do an action in HomeDropDownView I want to call a delegate method in HomeView and have that delegate method present a third view controller, TestViewController from it's navigation controller.
If I try to launch TestViewController from anywhere in the class it works fine - except from the delegate method.
There are animations in HomeDropDownView but putting the call to the delegate method in the complition does not make the view controller appear. And in the case that I'm using this the animation's don't fire anyway; there's only a resizing without animation.
TestViewController's init does get called as well as the viewDidLoad but not the viewWillAppear and the view dose not appear.
Code:
HomeDropDownView
- (void)finalAction {
...
[self callDelegateAction];
...
- (void)calldelegateAction {
if ([self.delegate respondsToSelector:#selector(launchTestView)] ) {
[self.delegate launchTestView];
} else {
DLog(#"Error out to the user.");
}
}
HomeView
- (void)launchTestView {
//[self listSubviewsOfView:self.parentViewController.view];
NSLog(#"delegate method | self: %#", self);
TestViewController *tvc = [[TestViewController alloc] initWithNibName:#"TestViewController" bundle:nil];
//[self.navigationController presentViewController:tvc animated:YES completion:nil];
//[self.view.window.rootViewController presentViewController:tvc animated:YES completion:nil];
//[self.navigationController pushViewController:tvc animated:YES];
AppDelegate *appdelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appdelegate.tabBarController.navigationController presentViewController:tvc animated:YES completion:^() {
NSLog(#"Done!");
}];
}
None of the above approaches work. But if I put the exact same code into the viewDidAppear or put it in a button action method, it will work fine. At the time of calling the delegate method's self is HomeView and all the subviews, including the nav controller do seem to be there. This is in a tabcontroller-based project but I think that any of the above are acceptable ways to call the nav controller still.
What am I missing? Why does my delegate method not want to push/present a viewcontroller on HomeView's Nav controller? It's probably something I'm missing but I can't find a reason in the Apple Docs or any other thread.
Thanks for the help!
Sadly this turned out to be that HomeView was being changed underneath the execution of the message. So by the time the HomeView got the message call it was no longer the same HomeView object that had requested action in the first place. So it was not the same delegate.
This was done so that it would appear to the user that the same view was being used for different things.
But this is a good example of why you should not destroy and re-create critical views. We should have been using the same view and reloading the objects instead if we knew that we would be sending messages. Or had some notion of a control structure.
As part of my updating my apps to replace the deprecated presentModalViewController with presentViewController, I did some testing.
What I found was disturbing. Whereas presentModalViewController always works and there is no question about it working, I have found the presentViewController method often will not display my VC at all. There is no animation and it never shows up.
My loadView are called without problems, but the actual view does not appear.
So here is what I am doing:
User taps a button in my main view controller.
In the callback for that tap, I create a new view controller and display it as shown above.
The VC never appears (it is an intermittent problem though) but because this VC begins playing some audio, I know that its loadView was called, which looks like as follows.
My button-pressed callback is as follows:
- (void) buttonTapped: (id) sender {
VC *vc = [[VC alloc] init];
[self presentViewController: vc animated:YES completion: nil];
[vc release];
}
Here is my loadview in the VC class:
- (void) loadView {
UIView *v = [UIView new];
self.view = v;
[v release];
... create and addsubview various buttons etc here ...
}
Thanks.
Make sure the controller that calls the function has its view currently displayed (or is a parent to the one currently displayed) and it should work.
I'm having a problem with a ViewController.
In hierarchy i have 3 ViewController:
Login
Grid
Profile
From Login to Grid, there is no problem. But when i'm try to go from Grid to Profiel, Grid is dismissed, i'm using:
ProfileViewController *perfil = [[ProfileViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:perfil animated:YES completion:nil];
from a Table, but i try from a button action too.
I create other viewcontroller (testviewcontroller) and try to present it and the same problem.
The view is presented, when i set animated to "YES" the view is presented, but just when it finish the parent is dismissed.
To clarify:
From grid controller no matter what i do, when profile (or test) controller is presented, grid is dismissed automatically.
I never see something like that.
Can anyone help me?
New info:
I create a new controller and instead to go from login to grid, i'm tried to go from login to the new controller, and the same problem happen.
New info (more weird):
I have this 2 calls to present a controller:
- (IBAction)ingresar:(id)sender
{
aViewController *grilla = [[aViewController alloc] initWithNibName:nil bundle:nil];
grilla.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:grilla animated:YES completion:nil];
}
- (IBAction)registro:(id)sender
{
RegistroViewController *registro = [[RegistroViewController alloc] initWithNibName:nil bundle:nil];
registro.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:registro animated:YES completion:nil];
}
The first have the issue of magically dissapear, the second dont...
Ok,
i dont know why, but after trying almost everything (including re-installing Xcode) the problem was that in a controller, i was presenting other controller inside
viewDidAppear
i have used this many times before and never happened this, i only can believe that is karma saying "that was a bad practice, b**ch"
The thing is: I have a modalViewController presented with a button that triggers an IBAction like this:
-(IBAction)myMethod
{
[self dismissModalViewControllerAnimated:YES];
if([delegate respondsToSelector:#selector(presentOtherModalView)])
{
[delegate presentOtherModalView];
}
}
in the root view that is the delegate for that modalViewControllerI've implemented the presentOtherModalView delegate method and it looks like this:
-(void)presentOtherModalView
{
AnotherViewController *viewInstance = [[AnotherViewController alloc]initWithNibName:#"AnotherViewController" bundle:nil];
viewInstance.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:viewInstance animated:YES];
[viewInstance release];
}
The problem is this second modalViewController is not being presented. It gives me the message wait_fences: failed to receive reply: 10004003... How should this be done?
Because they are executed exactly after each other (they don't wait for the view to disappear/appear), it doesn't get executed. Because there can only be one ModalViewController on the screen at a time, you have to first wait for the other ModalViewController to disappear before the next one is put on screen.
You can do this creatively how you want, but the way I did it was something like:
[self dismissModalViewControllerAnimated:YES];
self.isModalViewControllerNeeded = YES;
And then in the underlying ViewController, in the viewDidAppear method, I do this:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.isModalViewControllerNeeded) {
[self presentModalViewController:viewInstance animated:YES];
self.isModalViewControllerNeeded = NO;
}
}
Hope it helps!
It is because the dismissModalViewControllerAnimated takes some time to dismiss with animation and you are calling another view to present as modal view before dismissing the 1st modal view so the presenting modal view call was rejected. You should not perform animations when you are not on the view after completely dismissing only you can call another view. To solve this problem call the present modal view after 2 or 3 seconds using time interval or use completion block for dismissModalViewControllerAnimated
You can achieve it by using this
[delegate performSelector:#selector(presentOtherModalView) withObject:nil afterDelay:3];