How to present view controller from a class method of UIViewController - objective-c

I have a subclass of UIViewController. In order to present an alert in its instance method I would do
[self presentViewController:alert animated:YES completion:nil];
This time I need to present this alert in a class level method. There is no known class method for selector 'presentViewController:animated:completion:'
Is there any workaround?

Related

dismissViewControllerAnimated shows a white screen

I got a ViewController named viewControllerA which presents ViewControllerB with this common code:
ViewControllerB *viewControllerB = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"Identifier"];
[self presentViewController:viewControllerB animated:YES completion:nil];
viewControllerB is a UITabbarController but when calling
[self dismissViewControllerAnimated:YES completion:nil];
from one of the TabbarControllers ViewControllers (say page 2) I just get a white screen. I was expecting to see viewControllerA but instead I just see an empty screen.
also
NSLog(#"%#", [[self presentingViewController] class]);
logs viewControllerA.
Does anybody know why I get a empty white screen instead of viewControllerA?
EDIT
I put a breakpoint on viewDidAppear in viewControllerA and it does break there when calling dismissViewControllerAnimated. But how is it possible that it only shows a white screen?
Also I think you should know that viewControllerA's layout is created programatically. viewControllerB is created much later and in the meantime we decided to use a storyboard so viewControllerB's layout is created with storyboard.
you can remove your self (in viewcontrollerB)
[self.presentingViewController dismissViewControllerAnimated:NO completion:nil];
If you present viewControllerB from viewControllerA using
[self presentViewController:viewControllerB animated:YES completion:nil];
you should probably call [self dismissViewControllerAnimated:YES completion:nil]; in the viewControllerA, but not from one of the of the pages of your TabBarViewController.

Dismiss a Modal-Presented UITabBarController

EDIT: Added code that contains the dismissal.
NEW DATA
The problem remains the same as the problem listed under old data, except the dismissal line has changed.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Yes"])
{
NSLog(#"Calling Dismissal...");
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
}
The function is being called because "Calling Dismissal..." is displayed in the log.
Current Hierarchy: UITabBarController - NavigationController/NavigationController - View1/View2
OLD DATA
In case the question was confusing, I am trying to dismiss a UITabBarController than I presented modally. The UITabBarController does use NavigationControllers to setup the two views inside. However, no matter how many parentViewController s I put in
(i.e.):
[self.parentViewController.parentViewController.etc... dismissViewControllerAnimated:YES completion:nil];
The UITableBarController will not dismiss. I have a button being placed in the NavigationController of both views that is calling the line of code above. Any hints on how to dismiss the UITableViewController?
The presenting view controller, which is not the same concept as the parent view controller, needs to dismiss it. This code:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
will typically do the trick.
However, depending on what this controller's function is, I usually prefer to have my presented controllers send a delegate message or NSNotification to the parent, so the parent can extract whatever data it needs before dismissal.

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];

Calling a segue in one class from another class

I have a UIViewController that calls a method on a singleton object in which, given a certain condition, displays a UIAlertView. When the user taps the button in the UIAlertView I want the UIAlertView to disappear (which at the moment it does) and then the UIViewController behind it to segue to another scene. My problem is that the UIAlertView is from the singleton class, while the segue needs to be performed on the UIViewController.
In Singleton.m:
-(void)alertView:(UIAlertView *)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *buttonTitle = [alertView buttonTitleAtIndex:buttonIndex];
if ([buttonTitle isEqualToString:#"Button!"]) {
[self performSegueWithIdentifier: #"Segue!" sender: self];
}
}
My question is what do i replace self with that will allow me to notify the UIViewController that it's time to do a segue?
'Notify' is a good word. :) I suggest having the view controller listen for a NSNotification that the singleton will post when it wants the segue to happen. Then the perform... code would move into the view controller method that's called in response to the notification.

How to present the same modalView after dismissing it once

I'm having some problem trying to present a modal view controller after it has been presented the first time, so I just start a little test method, it presents, dismisses and presents again the same controller modally.
// This is just test Code.
MYViewController *vc = [[MYViewController alloc] init];
[self presentModalViewController:vc animated:YES];
[self dismissModalViewControllerAnimated:YES];
[self presentModalViewController:vc animated:YES];
I get the error:
2011-11-15 09:50:42.678 Proyecto3[1260:11603] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller <RootViewController: 0x6d9d090>.'
The documentation does not add any clue here.
#David, make the MYViewController an instance variable, and initialize it like this:
if (myInstance==nil)
//create instance of MYViewController
//myInstance.delegate=self
//present modal VC
In MYViewController create a protocol to co-ordinate dismissing MYViewController may be on a done or cancel button. In the button action call some thing like
done
{
if([delegate respondsToSelector:#selector(willDismissModalView)])
{
[delegate willDismissModalView];
}
}
and in willDismissModalView method of your VC dismiss MYViewController. This way you can do it 'n' times.
In your code [self dismissModalViewControllerAnimated:YES];
will do nothing to the modalViewController,since here the "self" is the viewController from where you are trying to present a modalViewController "vc".Again you are presenting a modalViewController which is already presented.this will result in a termination.
You can dismiss the modalViewController vc in that viewController,here vc.
You cannot present/dismiss the view controller while it is animated, I think this works
MYViewController *vc = [[MYViewController alloc] init];
[self presentModalViewController:vc animated:NO];
[self dismissModalViewControllerAnimated:NO];
[self presentModalViewController:vc animated:YES];
But I don't really see any reason for doing it, why would you want to dismiss and re-present a modal view controller which is already presented?