Call a function when a view controller is on top - ios

I'm wondering if there is a method that would call when a view controller is loaded to the screen.
As an example, the user presses a button and a second view controller loads. When the view controller appears, it runs a function automatically.

There are several methods you can use in a ViewController to run functions depending when you need them to run. In your case, you should use
-(void) viewDidAppear:(BOOL)animated
This will run once the viewController is appearing on the screen. Be sure to also call [super viewDidAppear:animated] inside the method.
Other methods that may come in handy:
-(void) viewDidLoad
-(void) viewWillAppear:(BOOL)animated
-(void) viewWillDisappear:(BOOL)animated
-(void) viewDidDisappear:(BOOL)animated

Related

Is it necessary to call super in viewWillAppear?

I am trying to understand the scenario of the method calls to view did/will appear and disappear.
What I did is selecting the table cell (higlights in grey) , go to detail view and go back and deselect the selected row (remove the selected cell grey color).
Here are my methods:
-(void)viewDidAppear:(BOOL)animated {
DLog(#"%# did appear", self);
[super viewDidAppear:animated];
if (_isPushed) {
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
_isPushed=NO;
}
}
-(void)viewWillAppear:(BOOL)animated {
DLog(#"%# will appear", self);
[super viewWillAppear:animated]; //If I remove this super call , then it works fine and there is no delay in deselecting the table cell
}
-(void)viewWillDisappear:(BOOL)animated {
DLog(#"%# will disappear", self);
[super viewWillDisappear:animated];
}
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
_isPushed=YES;
}
So , when I put breakpoint the flow goes like this:
without super call:
while pushing to new VC:
current viewWillDisappear //makes sense
new viewWillAppear //makes sense
current viewDidAppear // doesnt make sense , y this should get called as the view is already appeared?
current viewWillDisappear // make sense
current viewDidDisappear //make sense
new viewDidAppear //make sense
while coming back from pushed VC:
current viewWillDisappear
new viewDidDisappear
current viewDidDisappear
new viewDidAppear
with super call:
while pushing to new VC:
current viewWillDisappear
new viewWillAppear
current viewDidAppear
current viewWillDisappear
current viewDidDisappear
new viewDidAppear
while going back from pushed VC:
current viewWillDisappear
new viewDidDisappear
current viewDidDisappear
new viewDidAppear
The flow is pretty much the same either I use super call or not.
But the problem I am facing is, when I use super call in viewWillAppear, there is a delay(around >1second) in deselcting the cell.
If I dont use the super call in viewWillAppear , there is no delay and the cell is deselcting (around <0.5 seconds)
I am not sure to use super call or not.
Can anyone please tell me why there is a delay in deselecting the cell?
Yes, the documentation states you must:
Discussion
This method is called before the receiver's view is about
to be added to a view hierarchy and before any animations are
configured for showing the view. You can override this method to
perform custom tasks associated with displaying the view. For example,
you might use this method to change the orientation or style of the
status bar to coordinate with the orientation or style of the view
being presented. If you override this method, you must call super at
some point in your implementation.
Generally yes, call super. I've seen weird things happen in nav controllers when I forget.
In this case, if you have a UITableViewController, try using its clearsSelectionOnViewWillAppear flag to clear the selection for you.
Yes It's necessary to write super.

UIViewController: detecting when view appears again

I have a UIViewController class that contains a WKWebView and implements WKNavigationDelegate.
I would like to detect when a the view controller appears again. I understand the method loadView but, if I push a new view on the stack and then go back from that view to the previous view (my view controller) which method is called on the view controller?
The method that will be called is viewWillAppear:.
If you push to next view then viewDidLoad will be called first
Then viewWillAppear, viewDidAppear
If you pop to previous screen again (your UIViewController) then
viewWillAppear will be called first and after entire view appears
then viewDidAppear will be called..
viewDidAppear is useful in the cases where any method called at viewWillAppear after that you can Load the data at ViewDidAppear..
The ViewControllers viewDidLoad method is only called once when the view is created for the first time.
// viewDidLoad is called only once when the view is created for the first time
- (void) viewDidLoad
{
[super viewDidLoad];
// do your code here
}
You can also implement the below two methods in side your ViewController.m class
// viewWillAppear is called just before the view is about to be appeared
- (void) viewWillAppear
{
[super viewWillAppear];
// do your code here
}
// is called when the view has appeared
- (void) viewDidAppear
{
[super viewDidAppear];
// do your code here
}

Why is viewWillAppear: called twice when my view controller is initially displayed?

I have an iOS 7 app with a side hamburger menu and a main table view controller where I display content. Whenever the user selects an item in my side menu, I'm hiding the side menu and I want to reload data in the main view controller. My initial thought was to put my data refreshing code in my main view controller's viewWillAppear:
But when I set a breakpoint in viewWillAppear:, I get 2 calls when the view controller initially appears, one from UIViewController itself, and another from [ECSlidingViewController viewWillAppear:] where the following line seems to call my viewWillAppear: again
[self.topViewController beginAppearanceTransition:YES animated:animated];
On the other hand, when I show the left menu and then hide it, my view controller's viewWillAppear: is not called this time, so data is not refreshed in my case.
Did I miss something in my configuration somewhere? Is that a bug or a feature? How should I use it?
PS: I used to use IIViewDeckController and I had the exact same problem, so I switched to ECSlidingViewController because it said that "Your view controllers will receive the appropriate view life cycle and rotation methods at the right time.".
As a matter of fact, I managed to do what I wanted with another library: https://github.com/romaonthego/RESideMenu
I had to implement delegate methods in order to call lifecycle methods on my view controller when menu is shown or hidden:
- (void)sideMenu:(RESideMenu *)sideMenu willShowMenuViewController:(UIViewController *)menuViewController {
[sideMenu.contentViewController viewWillDisappear:YES];
}
- (void)sideMenu:(RESideMenu *)sideMenu didShowMenuViewController:(UIViewController *)menuViewController {
[sideMenu.contentViewController viewDidDisappear:YES];
}
- (void)sideMenu:(RESideMenu *)sideMenu willHideMenuViewController:(UIViewController *)menuViewController {
[sideMenu.contentViewController viewWillAppear:YES];
}
- (void)sideMenu:(RESideMenu *)sideMenu didHideMenuViewController:(UIViewController *)menuViewController {
[sideMenu.contentViewController viewDidAppear:YES];
}
And viewWillAppear is not called twice initially.

iOS assure viewcontroller transition ended

I've a bunch of turn based games in my app, and I use the same animations to declare the starting player.
At the very end of viewDidLoad, I placed the code for declaration. It takes the screenshot of current view then blurs it a little, and labels appear to show the name of the starting player. The issue is sometimes it happens to fast that I got the screenshot of previous view and labels appear on the blurred screenshot of previous view.
My viewDidLoad looks like this:
-(void) viewDidLoad
{
[super viewDidLoad];
[self initializeThings];
[self layoutUI]; //In some of the games this part requires heavy processing,
//ie laying out a 2D array of buttons (20x20=400 of them)
[self showStartingPlayer];
}
I use the default transition style cover vertical in all VCs. I tried calling [self showStartingPlayer]; deferred by using performSelector with delay but different devices require different delay values so it is not a robust solution. Is there any other method I can use in viewcontroller lifecycle instead of viewDidLoad or any practical way of doing such a thing?
if you are using presentViewController: animated: completion:, i would take advantage of the completion block to notify the view controller that the transition is complete.
for example, you could add a public method called -(void)wasJustPresented to your view controller which calls the necessary UI layout.
Then, call this in your completion block. Ex:
[self presentViewController:newVC
animated:YES
completion:^(void){
[newVC wasJustPresented];
}];
This will ensure your view controller is notified right after it is done being presented.
viewDidLoad is called when the view of the view controller has been loaded, but it doesn't mean that it's actually visible on the screen.
You may use - (void) viewDidAppear: to do that.
You should try to call your method inside the viewDidAppear which is called as the view transition has finished.
-(void)viewDidAppear:animated
{
[super viewDidAppear:animated];
//put your call here
}

How to run viewDidAppear

I need to load some data into a view every time it is shown. The data changes, each time time view is shown, so I figure I can load the data in the method viewDidAppear. Unfortunately, I've found that viewDidAppear is not called each time the view is displayed.
The code that displays the view from any other view is....
[self clearView];
[self.view insertSubview:fifthViewController.view atIndex:4];
So I figured I could change it to the following to run viewDidAppear...
[[self.view insertSubview:fifthViewController.view atIndex: 4 viewDidAppear:YES];
Unfortunaely, this causes an error "bad receiver type 'void'
What do I need to do to insert the subview and also call viewDidAppear?
If you show the view by modifying ViewController.view visibility directly, you won't get viewDidAppear message by that. You need to use ViewController method to display the view, e.g. push controller into UINavigationController or using presentModalViewController method. You can use the hack like calling viewWillAppear: and viewDidAppear: manually, but I don't like the idea.
Thank you for the assistance with this question.
I have settled on the addition of a viewDidAppear in the method that inserts the subview.
Below is the code that is working for me at this time.
In the .m file of the highest level view controller, the following code sets up the viewDidAppear call and then inserts the fifth subview.
-(IBAction) loadFifthView:(id)sender
{
[fifthViewController viewDidAppear:YES]; // sets up viewDidAppear
[self clearView];
[self.view insertSubview:fifthViewController.view atIndex:4];
}
With the above code snippet in place, the following code snippet, located in the .m file of the fifth view controller reports that it is working.
- (void)viewDidAppear:(BOOL)animated
{
NSLog(#" xxxxxxxxxxxxxxxx inside viewDidAppear ");
}

Resources