When UIPageViewController calls the datasource with the viewControllerBeforeViewController and viewControllerAfterViewController methods, it is obtaining the view controller that will be displayed when the user swipes again. Is there a writable property in which it keeps this data until it needs to use it? The reason I ask is that I want the user to be able to swipe to go forward or backward, or simply tap to advance to the next slide. However, if I tap to advance from the first slide to the second (advancing using the setViewControllers method), I cannot swipe backwards; there is no back controller to go back to. This affects only the second slide. So I need to be able to set the previous controller programmatically.
Any help would be greatly appreciated.
Thanks.
I had the similar issue and discovered, that UIPageViewController store its cached View Controller pages in the childViewControllers array.
There is no access to the cached view controllers. You can maybe keep a pointer when you implement the Data Source methods to enable swiping:
– pageViewController:viewControllerBeforeViewController:
– pageViewController:viewControllerAfterViewController:
As described in Kelin's answer, the children array contains the "loaded" view controllers. This information can also be used for propagating changes among loaded view controllers. (A common scenario would be ending the refresh of a refresh control.)
In Swift you can do something like this:
for vc in children {
if let tableVC = vc as? UITableViewController {
tableVC.refreshControl?.endRefreshing()
}
}
(Where self is of type UIPageViewController)
Related
Throughout my app I use a navigation controller to push and pop my view controllers. When I pop from one ViewController, I check to see if I can reload the data in the previous one with this:
_ = self.navigationController?.popViewController(animated: true)
if let previousViewController = self.navigationController?.viewControllers.last as? AnimalsVC {
previousViewController.tableView.reloadData()
}
This works every time, but now I need to do the same with another view, but it's not apart of the navigation controller because I modally present (instead of pushing it to the navigation controller). Now there's no way I can access the previous ViewController like before and I can not figure out how to access the previous ViewController.
How can I access the previous ViewController to reload the tableview like the example code without accessing the navigation controller?
I know this is possible with notifications, but I prefer not to use that method if possible!
First of all, It's not necessary to access the previous ViewController to reload tableview(or any other func)
I recommend you to use Delegate to achieve the same feature.
Holding a reference to the previous viewController in the way you mentioned will make your app very hard to maintain when your app gets more complicated.
You can call tableview.reloadData() in viewWillAppear method in the controller that you present modally
I have a view controller. It has some data and values in it. Then it presents modally to another view and moves around and some stuff happens. Then at some point, you self.dismissViewController(). Once back at the original view, can I count on the original data being there? Any help is greatly appreciated. Thanks in advance!
They will not be affected unless you specifically write code to do that for you.
For example, if you call a network request in the viewDidLoad() and add the data to some views, labels, etc. Then you leave that ViewController and come back, nothing will change, i.e., the network request will not be called again.
If you do want to change values in the ViewController every time it appears, use the viewDidAppear() delegate method.
for reloading view on dismiss you must use viewWillAppear() because this working every time before rendering view
calling dismissViewController will remove the viewController. If you do not have a strong reference to the view controller stored elsewhere, dismissing it releases the memory associated with it.
If the presented view controller must return data to the presenting view controller, use the delegation design pattern to facilitate the transfer.
So if the data was not modified in the presented controller then it will be the same then you can depend on it
reference: Apple docs
In my test project I have a ViewController and a TableViewController controller embedded in a Navigation Controller. The ViewController is the main view, and the user can navigate to the TableViewController and then return back to the ViewController.
I am using a 'push' segue when going from ViewContoller>TableViewController, and the TableViewController is dismissed using [self dismissViewControllerAnimated:YES completion:nil]; when the user wishes to go back to ViewController.
In ViewController, I have a button that changes the text on a label:
-(IBAction)onButtonPress:(id)sender {
_myLabel.text = #"New Label Text";
}
When navigating to TableView, and then back to ViewController, the change in the _myLabel.text has been lost and the original text is restored. What is the best way to ensure UI data is retained when navigating between views? I might only have one label in this project, but at some point I will have many UI elements, for example, WebViews that need to keep a page loaded when the user navigates away and then comes back.
What would you suggest is the best method to implementing this?
Thanks for your time.
First of all, View is your data representation, any data is your Model. So you may store Model with its entities and values. Your controllers manage data to represent it on View or to change Model according to user actions in View.
So add some Model-object for storing _myLabel.text. And use this object for both controllers in your app.
Try to remove setting the text from the ViewWillAppear or ViewDidAppear method, put it in ViewDidLoad.
I am navigating between screens in my iOS application.
BaseView.NavigationController.ViewControllers
As I switch screens, I keep a reference to the previous screen in a static variable.
At some point, one of my items gets removed from BaseView.NavigationController.ViewControllers even though it's still a valid viewcontroller and IsLoaded is still set to True/YES.
When I use (pardon my C#/MonoTouch)
BaseView.NavigationController.PopToViewController(CurrentViewController,false);
to show it again, I get NSInternalInconsistencyException Reason: Tried to pop to a view controller that doesn't exist. This is understandable because it's no longer in the ViewController collection.
The way I am switching screens is I am keeping a reference to he various screens and calling a common method to show the screen. In that method I use this logic to determine if I should push or pop.
if (CurrentViewController.IsViewLoaded)
{
BaseView.NavigationController.PopToViewController(CurrentViewController,false);
}
else
{
BaseView.NavigationController.PushViewController(CurrentViewController,true);
}
My question is where did it go and why would it have been removed from ViewControllers collection and when it's StillLoaded=true/YES?
If I understand correctly, you're using NavigationController.PopToViewController(controller); to navigate back to a certain view controller but keep a reference of the View Controllers that are popped from the navigation stack.
What I think is happening is because you're keeping a reference to these View Controllers, they're still in memory and thus the IsViewLoaded property is still true despite the View Controller not actually existing on the navigation stack.
Rather than using the IsViewLoaded property, you should check whether the View Controller exists in the NavigationController.ViewControllers array, if it does then Pop to it, if it doesn't then push it.
E.g.
if (BaseView.NavigationController.ViewControllers.Contains(CurrentViewController))
{
BaseView.NavigationController.PopToViewController(CurrentViewController,false);
}
else
{
BaseView.NavigationController.PushViewController(CurrentViewController,true);
}
Edit
So you mention you'd like a view to persist on the navigation stack. Well, using PopToViewController will remove ALL View Controllers between the TopViewController and the specified Controller.
In order to achieve what you're wanting, you could directly manipulate the NavigationControllers.ViewControllers array. Only problem with this is you'll lose the nice animations that the Push/Pop methods provide.
// Changes order of View Controllers currently in the stack. You can also add/remove
// controllers using this method.
NavigationController.ViewControllers = new UIViewController[]{
NavigationController.ViewControllers[1],
NavigationController.ViewControllers[0],
NavigationController.ViewControllers[3],
NavigationController.ViewControllers[2]};
which method will be called when i switch between tabs in tabBarController
i know at first time it will call viewDidLoad method ,i want to know is there any method that come in action when i switch to a particular tab (second time or third time ) .
regards
You can use the UITabBarControllerDelegate method tabBarController:didSelectViewController::
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
//do something
}
The method viewWillDisappear: is triggered each time you are about to leave the current view controller (and hence the current tab) and viewWillAppear: is triggered each time a view is about to be displayed.
A full reference for these methods can be found in the UIViewController docs.
This is pretty old, but it does come up on Google and is linked to from another answer. So, I thought I'd update it.
If your UITableBarController is displaying a UIViewController (i.e. its view) then you have to check the ViewController methods that fire when a view disappears and appears. You could use viewWillDisappear to find out if your view is about to be switched away from, and viewWillAppear to test if your view just got switched back to. Notice, the TabBarController typically keeps the ViewControllers loaded, just their views are moved out and in. The problem with using the TabBarDelegate method is that you need to know the name of your viewController, which makes that a dependency. Change the name and it will probably break with xcode's poor ability to rename Class String representations. Avoid it. Besides you don't want a bunch of conditional junk checking to see if your tabbar just loaded a particular tab unless you cannot avoid it. The other thing to notice is that if a particular tab presents a TableViewController you may have to resort to other techniques if you need data in the cells to change in response to being switched away from. I'm using willMoveToWindow:(UIWindow *)newWindow to get notified in the UITableViewCell case when the view goes away. There's probably a better way.