Present View Controller from another class - ios

I am trying to present a new viewcontroller from a class outside of that viewcontroller.
It looks like this:
AppDelegate.m -> inside has this code:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
Now, inside of that method is an object which utilises another class: [actionSheet launchActionSheetNav]; this simply makes an actionsheet appear with different options.
Now, inside of ActionSheets.m is some code, involving a segue as follows:
handler:^(AHKActionSheet *as){
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[vc presentViewController:vc animated:YES completion:nil];
}];
All I want to do, is launch a new view controller from inside of there, however doing [self.navigationController brings an error that ActionSheets.m does not contain such method/property.
How can I present a viewcontroller from outside the original classes?
So the hierarchy is as follows:
Viewing Storyboard > Listening on AppDelegate.m > Inside that, a class method is called which takes you to ActionSheets.m -> and from there I need to display the new viewcontroller.

This line:
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
Creates a new instance of ViewControllerYoutube. This ViewController doesn't exist anywhere else but that line, so when you follow it with this:
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[vc presentViewController:vc animated:YES completion:nil];
You're trying to present on a view controller that hasn't yet been presented.
If you want to present from an outside class, you need some way to keep a reference to the view controller you want to present, perhaps in your ActionSheet.h
#property (weak, nonatomic) ViewControllerYoutube *myViewControllerYoutube;
Then assign it when you create your action sheet (assuming you create it in ViewControllerYoutube)
ActionSheet * myActionSheet = [[ActionSheet alloc]init];
myActionSheet.myViewControllerYoutube = self;
Then instead of this:
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[vc presentViewController:vc animated:YES completion:nil];
Call this:
[_myViewControllerYoutube presentViewController:vc animated:YES completion:nil];
UPDATE
Based on our chat, here's how I think we can solve it.
In ActionSheet.h:
#property (weak, nonatomic) UIViewController *presentingViewController;
In 'ActionSheet.m'
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[_presentingViewController presentViewController:vc animated:YES completion:nil];
In your AppDelegate:
ActionSheet * actionSheet = [[ActionSheet alloc]init];
UITabBarController * tabController = (UITabBarController *)self.window.rootViewController;
actionSheet.presentingViewController = tabController.selectedViewController;

you need to do
[currentViewController presentViewController:vc animated:YES completion:nil];
do you have any reference to "correntViewController" from this block? from this class?
if not, do this
add a property
#property(nonatomic,strong) UIViewController *currentViewController
in the given class
then in your init method, or in the usual setCurrentViewController:
pass the reference to the controller,
and change you[vc presentViewController:vc animated:YES completion:nil];
to
[self.currentViewController presentViewController:vc animated:YES completion:nil];

Related

How to present a view controller programmatically

I have a button inside my nib file. How can I programmatically present another view controller when the user taps on this button?
As I understood , you want to push new viewController on Button click . Please try this
- (IBAction)buttonClicked {
MyViewController *myViewController = [[MyViewController alloc]init];
[self presentViewController: myViewController animated:YES completion:nil];
}
First you need to create an action for your button, normally via Ctrl+drag. On that action implementation you should alloc the destination ViewController. The code would be something like this:
- (IBAction)buttonTapped {
MyViewController *modalViewController = [MyViewController new];
[self presentViewController:modalViewController animated:YES completion:nil];
}
Since you said that your file is a nib, I'm assuming that you aren't on a storyboard with both ViewControllers on it and the ViewController to be presented is code based. If this isn't the case, please elaborate your question.
As requested: Loading a VC from a storyboard
- (IBAction)buttonTapped {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MyStoryboard" bundle:nil];
RSSViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"RSSVC"];
// OR If is initial
// RSSViewController *viewController = [storyboard instantiateInitialViewController];
viewController.feedURL = #"...";
[self presentViewController:viewController animated:YES completion:nil];
}
If you need, ViewController identifier should be set in the Identity Inspector in the Storyboard.
Refer the below screenshots
First : control+drag the button
Second: Once you release the mouse,it shows you the box
Third:Click Connection Dropdown box.It shows you 3 option
Fourth:Choose or Select Action from the drop down.
Five : Finally give action name
now in ViewContoller.h the action method is
- (IBAction)actionGoNextPage:(id)sender;
Then in ViewContoller.m
#import "SecondViewController.h"
- (IBAction)actionGoNextPage:(id)sender
{
SecondViewController *secondVC = [[SecondViewController alloc]initWithNibName:#"SecondViewController" bundle:nil];
[self presentViewController:secondVC animated:YES completion:nil];
}

how to add New UIViewCOntroller Over UiView

I have added subview in a UIViewController and I want a new UIViewController Should be loaded on click of button.
Challenge is I am not able to use button in new UIViewController.
Code which I have write:
DetailsOfDayViewController *aViewController =[[DetailsOfDayViewController alloc] initWithNibName:#"DetailsOfDayViewController" bundle:nil];
aViewController.dateParsing = dateparsing;
[self addSubview:aViewController.view];
This will fix your issue. This is happening because your view controller is being deallocated when you don't have any strong pointers on it.
DetailsOfDayViewController *aViewController =[[DetailsOfDayViewController alloc] initWithNibName:#"DetailsOfDayViewController" bundle:nil];
aViewController.dateParsing = dateparsing;
[self addChildViewController:aViewController];
[self addSubview:aViewController.view];
Another fix will be connecting this view controller to a property:
#property(nonatomic,strong) DetailsOfDayViewController *aViewController;
And change your code like this:
self.aViewController = [[DetailsOfDayViewController alloc] initWithNibName:#"DetailsOfDayViewController" bundle:nil];
self.aViewController.dateParsing = dateparsing;
[self addSubview:self.aViewController.view];
For showing another controller you can following options
1. Add SubView
newViewControllerObj.view.frame = oldViewControllerObj(self).view.frame
[oldViewControllerObj(self).view.newViewControllerObj.view];
2. Present
[oldViewControllerObj(self) presentViewController: newViewControllerObj animated:YES completion:nil];
3. Push using Navigation (For this you already have to set navigation controller as root controller)
[oldViewControllerObj(self).navigationController pushViewController:newViewControllerObj animated:YES];

presentViewController didnt work appdelegate

line presentViewController crash app
#interface VVPassbook : NSObject
#property (nonatomic, retain) id delegate;
-(void)gotPassbookFromUrl:(NSURL *)passbookUrl;
#end
#import "VVPassbook.h"
#implementation VVPassbook
-(void)gotPassbookFromUrl:(NSURL *)passbookUrl
{
//present view controller to add the pass to the library
PKAddPassesViewController *vc = [[PKAddPassesViewController alloc] initWithPass:pass];
[vc setDelegate:(id)self.delegate];
[self.delegate presentViewController:vc animated:YES completion:nil];
}
#end
im call this method in AppDelegate.m in method
- (void)application:(UIApplication*)application didReceiveRemoteNotification:
(NSDictionary*)userInfo
{
VVPassbook *pass = [[VVPassbook alloc] init];
pass.delegate = self.window.rootViewController;
[pass gotPassbookFromUrl:MYURL ];
}
all times error
reason: 'Application tried to present a nil modal view controller on target <VVRightManuViewController: 0x15dd28460>.'
you should present a viewController from a UIViewController, i.e., self
(if self is a viewcontroller).
Note that you will get a "Attempt to present on whose view is not in the window hierarchy"-warning when self (this viewcontroller) is detached from the Main Window.
Solution: always use addChildViewController: to child viewcontrollers.
Why are you using self.delegate to push the view Controller,
simple write
[self presentViewController:vc animated:YES completion:nil];
in the place of
[self.delegate presentViewController:vc 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.

Change view in one XIB

I'm trying to make an app using Interface Builder (instead of Storyboard) for the first time, but I'm stuck. Is it possible to change view using a ViewController in the same XIB?
I'd like that when I tap a button, the view changes to the other ViewController present in the same XIB file. Must I call back an action? If yes, which?
If you have 2 view controllers with 2 .xib files, like this
You can present the NextViewControler from your ViewController's button press method,
-(IBAction) yourButtonPressed:(id)sender;{
NextViewController *nextViewController = [[NextViewController alloc] initWithNibName:#"NextViewController" bundle:nil];
[self presentViewController:nextViewController animated:YES completion:nil];
}
EDIT :
You can present the same viewcontroller like this.
-(IBAction) yourButtonPressed:(id)sender;{
ViewController *viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
[self presentViewController:viewController animated:YES completion:nil];
}

Resources