Calling method from self.parentViewController does nothing - ios

After dismissing my second view controller, I would like to call a function in my first view controller.
The code I am using now is this
firstViewController *fvc = (firstViewController *)self.parentViewController;
[self dismissViewControllerAnimated:YES completion:^ {
[fvc someMethod];
}];
But it seems that the method is never called, I added a UIAlertView to the method so it would be called the moment the method is called too.
firstViewController *fvc = (firstViewController *)self.parentViewController;
[fvc someMethod];
[self dismissViewControllerAnimated:YES completion:nil];
This totally fails too, I don't get any error from both ways.

firstViewController *fvc = (firstViewController *)self.parentViewController;
[self dismissViewControllerAnimated:YES completion:^ {
[fvc someMethod];
}];
You should use presentingViewController insteadof parentViewController when self is being presented
like
firstViewController *fvc = (firstViewController *)self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^ {
[fvc someMethod];
}];

As rdurand said, try presentingViewController instead. Also, would be very helpful if you could put in a NSLog() in your code to show you what's in fvc at the point of method invocation. rdurand is probably right that your fvc pointer is nil, so you're invoking the method on nothing. If the method isn't activating, then there are really only a few possibilities:
Your line of code is not executing
It's executing, but you're invoking the method on a nil object
The method is executing, but on a different object than you're expecting
Set a breakpoint, look at your VC pointer, make sure the code is following the path you think it is. Pretty standard debugging task, unless I'm missing something...

As I commented, the UIViewController documentation states :
parentViewController
The parent view controller of the recipient.
(read-only)
#property(nonatomic, readonly) UIViewController *parentViewController
Discussion
If the recipient is a child of a container view controller,
this property holds the view controller it is contained in. If the
recipient has no parent, the value in this property is nil.
Prior to iOS 5.0, if a view did not have a parent view controller and
was being presented, the presenting view controller would be returned.
On iOS 5, this behavior no longer occurs. Instead, use the
presentingViewController property to access the presenting view
controller.
So basically, they did not really remove parentViewController, but the behavior you could expect before iOS 5 when your view controller doesn't have a parent view controller has changed.

Related

Button Click To Call First Viewcontroller To Another Viewcontroller Method Using Objective C?

I have multiple UIViewController objects within one main UIViewController. I need to call FVC method when I click the main view controller button. Here three view controllers having three separate class files.
From your first controller on didSelectRowAtIndexpath method,
UIStoryboard * board = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController * cntrl = [board instantiateViewControllerWithIdentifier:#"ViewController"];
[self presentViewController:cntrl animated:YES completion:^{
}];
add above code. Here ViewController is nothing but a your Second view controller. Using reference of cntrl pass data to Second controller.
When you want to navigate to any other controller without having navigation controller reference , you use present view controller.
If you are trying to call a method present in other ViewController without presenting it, I guess you are doing it wrong, because that method belongs that ViewController class and ideally should be called when that ViewController's lifecycle is in progress.
For your scenario, I suggest that you should create a utility class, move that method which accepts two strings and then processes something in that utility class and then call that method from your ViewController1 something like :
[UtilityClassName yourMethodWithFirstString : str1 andSecondString : str2];
Hope that clears.
UIViewController *viewVC = [[UIViewController alloc] init];
[self presentViewController:viewVC animated:YES completion:nil];
//Loading a view controller from the storyboard
UIViewController *viewVC = [self.storyboard instantiateViewControllerWithIdentifier:#"IDENTIFIER_OF_YOUR_VIEWCONTROLLER"];
[self presentViewController:viewVC animated:YES completion:nil];
In First View Controller
//Do this inside your btnCall method
SecondViewController * cntrl = [self.storyboard instantiateViewControllerWithIdentifier:#"secondViewControllerIdentifier"];
[cntrl methodName:firstParameter:secondParameter];
In SecondViewController
In .h file
-(void)methodName:firstParameter:secondParameter;
In .m file
-(void)methodName:firstParameter:secondParameter{
//Do your task here
}

dismissViewController completion:, need to load function, can't get it to work

Calling Code here within GameListViewController:
[self presentViewController:[[StartNewGameViewController alloc]
initWithNibName:#"StartNewGameViewController" bundle:nil] animated:YES completion:nil];
Callback Code here within StartNewGameViewController:
[(id)self.parentViewController showSetup:m_tableID];
[self dismissViewControllerAnimated:YES completion:^{
[GLVC showSetup:m_tableID];
}];
Also have tried:
[(id)self.GLVC showSetup:m_tableID];
Tried three different methods above here. The first method has no error, bottom method says show Setup has no known class method, third method also no error. First and third have no errors, but are not working.
.h of StartNewGameController
#import "GamelistViewController.h"
#property (nonatomic, assign) GamelistViewController *GLVC;
And I synthesize GLVC on the top of the .m
"showSetup" is a method that works just fine while called from GameListViewController and is declared in GameListViewController.h like so:
-(void)showSetup:(int)tableID;
I've seen some other stack overflow questions related to this one, but none of them have resolved my issue.
[(id)self.parentViewController showSetup:m_tableID];
works because the reference to parentViewController is automatically configured for you.
[GLVC showSetup:m_tableID];
should be _GLVC or, preferably self.GLVC and doesn't work because you never set the reference before you present the view controller. (previously it didn't work because you were using a class name, expecting it to be an instance variable name, due to bad naming, but it wasn't).
[(id)self.GLVC showSetup:m_tableID];
Is really the same as the above (in your new edited code).
The solution is to set GLVC on the created view controller before you call presentViewController:animated:completion:
StartNewGameViewController *svc = [[StartNewGameViewController alloc] initWithNibName:#"StartNewGameViewController" bundle:nil];
svc.GLVC = self;
[self presentViewController:sec animated:YES completion:nil];
This code will do the stuff i guess. presentingViewController will automatically set it for you while presenting the controller.
[self dismissViewControllerAnimated:YES completion:^{
[(id)self.presentingViewController showSetup:m_tableID];
}];

iOS Delegate Does Not Push or Present a View

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.

viewDidDisappear not called when use presentViewController

I have an UIViewController having this method:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
NSLog(#"DISAPPEAR");
lastKnownOrientation = [self interfaceOrientation];
}
-(void)openSendVC{
SendMsgViewController *vc = [[SendMsgViewController alloc]initWithNibName:#"SendMsgViewController" bundle:nil];
[self.navigationController pushViewController:vc animated:NO];
}
In the second view controller (SendMsgViewController) viewDidLoad I have the following:
[self presentViewController:picker animated:YES completion:NULL];
where picker is an UIImageViewPicker.
The problem is, when I call the method openSendVC a new controller is opened, but viewWillDisappear (of the first viewController) is not called.
That is the correct behavior. Here's an excerpt about viewWillDisappear: from the UIViewController API docs:
This method is called in response to a view being removed from a view hierarchy. This method is called before the view is actually removed and before any animations are configured.
Presenting a new view controller so that it hides the other view controller doesn't count as the view disappearing—only actually being removed from a view hierarchy does (e.g., with something like popViewControllerAnimated:).

iOS: How to get pointer to navigation controller

I'm obviously missing something...
In my iOS app, I push a UIViewController onto a navigation controller:
MyViewController *mvc = [[MyViewController alloc] initWithNibName:#"MyViewController"];
[self.navigationController mvc animated:YES];
MyViewController displays fine, and I can see and use the navigationBar, but when I try to get a pointer back to the navigation controller from within my view controller, I get a nil result.
UINavigationController *nav = [self navigationController];
if (!nav) {
NSLog(#"no nav");
}
I've been beating my head against this all day, but can't see that I'm doing anything wrong. I get no warnings or errors in Xcode. Am I completely missing something?
TIA: john
The navigationController won't be set properly on viewDidLoad. You have to check it in viewDidAppear or at some later stage. Which method are you calling to [self navigationController] in?
The reason for this is that when viewDidLoad is called, the UINavigationController is still processing the pushViewController:animated: method. It would appear to set the navigationController property after it initialises the controller's view. I can't recall whether the property is set by the time viewWillAppear runs, but it should definitely be set by viewDidAppear.
id rootViewController = [[[[[UIApplication sharedApplication] keyWindow] subviews] objectAtIndex:0] nextResponder];

Resources