presentViewController didnt work appdelegate - ios

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

Related

nil delegate in modal view after presentViewController.

My first view in the viewDidLoad has the following code
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Dialpad" bundle:nil];
self.vc = [sb instantiateViewControllerWithIdentifier:#"DialpadBoard"];
self.vc.delegate = self;
The header file contains the definition of the view controller
#property (nonatomic, retain) DialpadTableViewController *vc;
after catching an event the view loads a new modal view
- (void)handleEvent:(UIGestureRecognizer*)recognizer {
[self presentViewController:self.vc animated:YES completion:NULL];
}
The view also contains the method to dismiss the modal view:
- (void) dialpadControllerDidCancel:(SearchDialpadTableViewController *)controller {
[self dismissViewControllerAnimated:YES completion:nil];
}
The last method never gets called.
The problem is that the modal view when it is loaded has nil self.delegate. The new modal view is loaded from the storyboard as seen below. Why the delegate is nil? I cannot how a segue since the view is in another storyboard.
you can try this
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Dialpad" bundle:nil];
UINavigationController *nav= [sb instantiateViewControllerWithIdentifier:#"DialpadBoard"];
((SearchDialpadTableViewController *)[nav viewControllers][0]).delegate = self;
[self presentViewController:nav animated:YES completion:NULL];
Since we have the nav let's take the first controller and assign the delegate
the trick ;)
((SearchDialpadTableViewController *)[nav viewControllers][0]).delegate = self;
Does SearchDialpadTableViewController define a delegate protocol and does it have a property that is specific to that protocol?
The header for that file should look something like:
#protocol ViewControllerDelegateProtocol <NSObject>
- (void)dialpadControllerDidCancel:(SearchDialpadTableViewController *)controller;
#end
#interface ViewController : UIViewController
#property (weak, nonatomic) id<ViewControllerDelegateProtocol> searchPadDelegate;
#end
Then when the user taps Done which is I'm assuming what you're trying to do (send a delegate message when that happens). You would write something like
- (IBAction)donePressed:(id)sender
{
if ([self.searchPadDelegate respondsToSelector:#selector(dialpadControllerDidCancel)]) {
[self.searchPadDelegate dialpadControllerDidCancel:self];
}
}
you must be certain, that self.vc is a class, that you expected. It can be also NavigationController

Present View Controller from another class

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

Property nil when using delegate to pass data back to VC

I've got a view in a xib file that I load to my viewController - its a temp view and thus isn't on screen all the time. However the temp view and the main view, use the same view controller class as they both are doing the same job.
Now, in the xib view I load up a second viewControoler - lets call it viewControllerB - which is a UITableView with 197 cells. Once a cell is selected, the view is dismissed and the value of the cell is returned to viewControllerA.
viewControllerB is on the storyboard.
Here is the code I have used:
viewControllerB (The VC I need data back from)
Delegate Protocol:
#protocol CountrySelectedDelegate <NSObject>
-(void)selectedCountry: (id)countryReturned;
#end
#property (strong, nonatomic) id <CountrySelectedDelegate> myDelegate;
Then in the .m file:
Set the delegate:
ViewControllerA *viewA = [[ViewControllerA alloc]init];
self.myDelegate = viewA;
Then I call the delegate in the same file;
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[self myDelegate] selectedCountry:indexPath.row];
[self dismissViewControllerAnimated:YES completion:nil];
}
Now in viewControllerA:
pragma mark - CountrySelected Delegate
-(void)selectedCountry:(id)countryReturned
{
self.testInt = countryReturned;
}
Now this method does get called by the delegate. Looking in the console: countryReturned is the correct value. Once this method has finished, self.testInt is also the correct value.
Then, in my viewWillAppear method, I simply check the value again to see if its still the same with a NSLog print.
the value is always nil in the viewWillAppear method (Or anywhere else I check it) - I have tried with NSMutableString and NSString - always nil.
Why are my properties / instance variables getting set to nil?
Update:
This is how I show viewControllerB
- (IBAction)countrySelect:(UIButton *)sender
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
UITableViewController *vc = [sb instantiateViewControllerWithIdentifier:#"CountrySelection"];
vc.modalTransitionStyle = UINavigationControllerOperationPop;
[self presentViewController:vc animated:YES completion:NULL];
}
On ViewB do the below I guess you have already done
#protocol CountrySelectedDelegate <NSObject>
-(void)selectedCountry: (NSInteger)countryReturned;
#end
#property (week, nonatomic) id <CountrySelectedDelegate> myDelegate;
and in didSelectRowAtIndexPath
if ([[self myDelegate] respondsToSelector:#selector(selectedCountry:)])
{
[[self myDelegate] selectedCountry:indexPath.row];
}
On ViewA
Conform the protocol
#interface ViewA : UIViewController < CountrySelectedDelegate >
create the call ViewB
ViewB *viewBObjc=[[ViewB alloc] init];
[viewBObjc setMyDelegate:self];
[[self navigationController] presentViewController:ViewB animated:YES completion:Nil];
implement the delegate on ViewA
-(void)selectedCountry: (NSInteger)countryReturned
{
NSLog(#"Country Id is :%d", countryReturned);
}
Try this,
Set delegate by
//in ViewControllerB
self.myDelegate = [self parentViewController];
or
- (IBAction)countrySelect:(UIButton *)sender
{
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
ViewControllerB *vc = (ViewControllerB *)[sb instantiateViewControllerWithIdentifier:#"CountrySelection"];
vc.modalTransitionStyle = UINavigationControllerOperationPop;
vc. myDelegate = self;
[self presentViewController:vc animated:YES completion:NULL];
}

Calling a Function in MasterView after dismissing the ModalView in ipad

I am using Master-Detail template for ipad. I have a ViewController, which I want to show modally so I have used this code
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
m_ViewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
m_ViewController.modalPresentationStyle = UIModalPresentationFormSheet;
[appDelegate.splitViewController presentModalViewController:m_ViewController animated:YES];
This works fine and the ViewController is loaded modally, Now I tried to dismiss this ViewController, So inside ViewController.m, I called this line of code
[self dismissModalViewControllerAnimated:YES];
This code also works fine and the ViewController gets dismissed, But after dismissing I want to call a function in my MasterView. How to do that?
Code added according to the discussion with Moxy.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.testViewController testfunction:testImage];
As amit3117 pointed out, you should use a delegate.
The protocol should be defined at least with a method that would communicate to the delegate that the view controller that was presented modally did finish its work.
#class ViewController;
#protocol MyViewControllerDelegate <NSObject>
-(void)viewControllerDidFinish:(ViewController *)sender;
#end
EDIT : I forgot to add that you should a public property for the delegate to ViewController
#interface ViewController : UIViewController
#property (nonatomic, weak) id <MyViewControllerDelegate> delegate;
#end
You could use your master view controller as the delegate. So in your master view controller implementation you would also have :
#interface MyMasterViewController () <MyViewControllerDelegate>
#end
#implementation MyMasterViewController
-(void)showViewController
{
m_ViewController = [[ViewController alloc] initWithNibName:#"ViewController"
bundle:nil];
m_ViewController.modalPresentationStyle = UIModalPresentationFormSheet;
m_ViewController.delegate = self;
// –presentModalViewController:animated: is deprecated!
[self.parentViewController presentViewController:m_ViewController
animated:YES
completion:nil];
}
-(void)viewControllerDidFinish:(ViewController *)sender
{
// Add any code you want to execute before dismissing the modal view controller
// –dismissModalViewController:animated: is deprecated!
[self.parentViewController dismissViewControllerAnimated:YES
completion:^{
// code you want to execute after dismissing the modal view controller
}];
}
#end
When m_ViewController finishes its work, it should call :
[self.delegate viewControllerDidFinish:self];

View controllers not being deallocated

I have 2 controllers InitViewController and SettingsViewController. Each view has a button that calls another view:
InitViewController
#interface InitViewController : UIViewController
- (IBAction)loadSettings:(id)sender;
#end
#implementation InitViewController
- (IBAction)loadSettings:(id)sender {
SettingsViewController *vc = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:nil];
[self presentViewController:vc animated:YES completion:nil];
vc = nil;
}
#end
SettingsViewController
#interface SettingsViewController : UIViewController
- (IBAction)back:(id)sender;
#end
#implementation SettingsViewController
- (IBAction)back:(id)sender {
InitViewController *vc = [[InitViewController alloc] initWithNibName:#"InitViewController" bundle:nil];
[self presentViewController:vc animated:YES completion:nil];
vc = nil;
}
#end
While I was profiling application and testing it by tapping buttons many times I saw that instances of InitViewController and SettingsViewController are still living =>
What am I doing wrong?
Your SettingsViewController doesn't return to the InitViewController that created it. Instead, it creates a new instance of InitViewController and presents that. So you end up with a stack of view controllers alternating between instances of InitViewController and SettingsViewController.
Since you never dismiss either type of view controller after presenting it, none of them can be deallocated.
Your -[SettingsViewController back:] action should dismiss itself rather than creating and presenting a new InitViewController.
#implementation SettingsViewController
- (IBAction)back:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}

Resources