In case I have 4 items in Tabar.
When open app, default is in TabBarItem[0] - ViewControllerRoot
I push from ViewControllerRoot into ViewController A. From ViewController A, I switch to TabBarItem[3] - contain ViewController B.
The question is: How can I get name of ViewController A when I switch to TabBarItem[3]?
Thank you so much.
You can get your current viewcontroller using selectedViewController.
User delegate method of tabbar.
func tabBarController(_ tabBarController :UITabBarController, shouldSelect: UIViewController){
let currentVC = tabBarController.selectedViewController
let destinationVC = shouldSelect
}
I hope this will work for you.
When you change the view from UITabBar there is a delegate method that is invoked
tabBarController:animationControllerForTransitionFromViewController:toViewController:
This will help you to find the previous selected controller.
Your question is a bit unclear..please share some code.
if you wish to get an the instance of ViewController A:
window.rootViewController?.childViewControllers[0]
if you wish to get the class name of ViewController A:
a = window.rootViewController?.childViewControllers[0]
var className: String = a.self
Related
i have three classes, where i have a container, mainview and a left menu.
App looks like this
When i press a button in the left menu, this execute an action in mainview:
var viewController: ViewController = ViewController()
func menuLeftButton1(){
self.viewController.doActionInMainView()
}
But, when i want to change a variable of the mainview in that function in debuger says that the varieble of maninview is null.
I think that the variables of the mainview are destroyed and i can't use them when i return from the left menu.
Other case is when i have a switch in the left menu and I enable it
and close the left menu and open again the switch looks like I haven't
enable it.
Can u help me with this case? Thanks.
I think problem is in this code:
var viewController: ViewController = ViewController()
You need to instatiate viewcontroller from a xib or storyboard
For storyboard you can do this:
You need to set the identifier of the view controller in storyboard
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewControllerIdentifier")
I want to know how to do this:
I have 3 view controllers and the first and second view controller are connected to the third one !
I want to know how can I write a code that detect from which one I came to this view controller
I have searched here for my answer But all of the similar questions asked about navigation !!!
The Important thing is that I don't have navigation in my app!!
I don't know if my answer will help you in your specific case, but here is the implementation I see from what you are asking. Maybe it will inspire you.
So imagine your are in your homePage or whatever viewController and you want to navigate throw other, but you want to know from which viewController you came from.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:segue_VC1]) {
CustomViewController1* destinationVC = segue.destinationViewController;
destinationVC.fromSegue = #"I AM VC 1";
}
if ([segue.identifier isEqualToString:segue_VC2]) {
CustomViewController2* destinationVC = segue.destinationViewController;
destinationVC.fromSegue = #"I AM VC 2";
}
}
The more important thing you have to know is that you can access attribute from the destination view controller you will access with your segue.
I know this is in Obj C, but the implementation is still the same.
So that when you navigate from a ViewController to an other one, you can set the attribute of the destinationViewController.
Then when you are in the view controller you wanted to navigate you can check :
if ([_fromSegue isEqualToString: "I AM VC 1"])
// do specific stuff when you come from VC 1
else if ([_fromSegue isEqualToString: "I AM VC 2"])
// do specific stuff when you come from VC 2
else
// other case
There are many ways to do that like simply passing a view controller as a property to the new instance. But in your case it might make more sense to create a static variable which holds the stack of the view controllers the same way the navigation controller does that.
If you are doing this only between the UIViewController subclasses I suggest you to create another subclass of it form which all other view controllers inherit. Let us call it TrackedViewController.
class TrackedViewController : UIViewController {
static var currentViewController: TrackedViewController?
static var previousViewController: TrackedViewController?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
TrackedViewController.previousViewController = TrackedViewController.currentViewController
TrackedViewController.currentViewController = self
}
}
Now you need to change all the view controllers you want to track so that they all inherit from TrackedViewController as class MyViewController : TrackedViewController {. And that is pretty much it. Now at any point anywhere in your project you can find your current view controller via TrackedViewController.currentViewController and the previous view controller via TrackedViewController.previousViewController. So you can say something like:
if let myController = TrackedViewController.previousViewController as? MyViewController {
// Code here if the screen was reached from MyViewController instance
}
Now the way I did it was through the instance of the view controller which may have some side effects.
The biggest problem you may have is that the previous controller is being retained along with the current view controller. That means you may have 2 controllers in memory you do not need.
If you go from controller A to B to C and back to B then the previous view controller is C, not A. This might be desired result or not.
The system will ignore all other view controllers. So if you use one that is not a subclass of TrackedViewController the call will be ignored: A to B to UITableViewController to C will report that the C was presented by B even though there was another screen in between. Again this might be expected result.
So if the point 2 and 3 are good to you then you should only decide weather to fix the point 1. You may use weak to remove the retaining on the two properties but then you lose the information of the previous view controller if the controller is deallocated. So another choice is to use some identifiers:
class TrackedViewController : UIViewController {
static var currentViewControllerID: String?
static var previousViewControllerID: String?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
TrackedViewController.previousViewControllerID = TrackedViewController.currentViewControllerID
TrackedViewController.currentViewControllerID = self.screenIdentifier
}
var screenIdentifier: String {
return "Default Screen" // TODO: every view controller must override this method and have unique identifier
}
}
Also you may replace strings with some enumeration or something. Combining them with some associated values could then create quite a powerful tool.
I have a main view controller which has the following tuple:
var textsForTabs = (tab1: "this is tab one text", tab2 : "this is tab 2 text")
from the main view controller i want this data to pass to a tab controller with 2 childs: tab 1 and tab 2 which have labels on them, the first tab should show in it's label the text from textsForTabs.tab1 and the second textsForTabs.tab2.
What are my options here and the best practice?
I tried to instantiate the tabbarcontroller and in it, get the first view controller and assign the value from the tupple to an instance variable, later to be used when view is being shown: like so:
let tabBarController = segue.destinationViewController as UITabBarController
let ftc = tabBarController.viewControllers![0] as firstTabController
let stc = tabBarController.viewControllers![1] as secondTabController
ftc.setLabelTxt(textsForTab.tab1)
stc.setLabelTxt(textsForTab.tab2)
I got that from here:
how to send data from UIViewController to UITabBarControllers first tab in swift ios
But i read somewhere this is hacky, what are my other options?
I suggest to set the label txt when viewDidLoad is called for both firstTabController and secondTabController
Here an example for firstTabController :
class FirstTabController: UIViewController {
override func viewDidLoad() {
if let tabBarController = self.tabBarController as? MyCustomTabBarController {
self.setLabelTxt(tabBarController.textsForTabs.tab1)
}
}
...
}
I am new developer and I am struggling with my Walkthrough screen for my application.
I have created it, but when I click continue to my main screen, the app crashes.
Here is the code I have under my "continue" button:
#IBAction func skipButtonTapped(_ sender: AnyObject) {
let nextView: FirstViewController = self.storyboard?.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
let appdelegate = UIApplication.shared.delegate as! AppDelegate
appdelegate.window!.rootViewController = nextView
}
and the error I get is :
Could not cast value of type 'UITabBarController' (0x19f33c0d8) to 'Iwin.FirstViewController' (0x100057220).
I think the Problem is in the name of the name of the identifier which in my case is "FirstViewController"
This is the storyboard ID of my TabBarController, which should be the first screen of my app.
Attached I have uploaded a picture too.
The error you are seeing probably has to do with the forced conversion (as!) you do on the first line of the function. You're doing the following:
Calling instantiateViewController(withIdentifier:), which Apple API Documentation says returns UIViewController (in this case, it's returning UITabBarController, a subclass)
Force converting a UITabBarController to a FirstViewController, which fails.
This is because forced conversion guarantees that the resulting value won't be nil, but it doesn't guarantee that it won't fail (crash). UITabBarController is simply not convertible, because it does not extend/implement FirstViewController.
My guess is that even though you've given that view controller the identifier "FirstViewController", but it's just a regular old UITabBarController. Double check in Interface Builder that this View Controller is actually an instance of your FirstViewController class.
Looking at your photo, the "Class" field has the default value of UITabBarController -- this should be the first thing you try to change. Fill in FirstViewController, and let me know if it works.
I'm trying to get the currently displayed ViewController using the following:
let currentViewController = UIApplication.sharedApplication().keyWindow!.rootViewController?.presentedViewController
This property gives me the TabBarController. The only property after presentedViewController is "childViewControllers".
How could I use this to attain the currently displayed ViewController?
If it is TabBar based Application then to check which is currently selected ViewController depends on following condition :
First Track which tabbar is selected e.g :Condition to check which Tab Index is selected
Maintain NavigationController for each TabBar
Then Check navigationcontroller stack last index to match up the ViewController . ( which is chilviewcontroller you can say).
Hope it helps .
You can access the selected view controller from the tabBarController. An easy way to do so is with this extension.
Just take note that it will not update with the correct value until viewDidAppear. Checking the property prior to that will give you your previous screen.
import UIKit
extension UITabBarController {
var displayedViewController: UIViewController? {
return selectedViewController
}
}