I want to pass data from a view controller to tabbar controller, and then from this tab bar controller to its view controller with using their class. I succeeded to transfer from view controller to tabbar controller using segue. However, I cannot transfer data from tabbar controller to its one of the view controller.
Any idea/documentation will be appreciated. Here is the screenshot about what I want to do from xcode
screenshot-xcode
Take a look at the documentation for the tab bar controller, in particular the viewControllers property.
That property is an array of UIViewControllers, in the order they appear in the tab bar, so you can pick the one you need (viewControllers[0] from your screen shot), cast it to your specific view controller subclass and then pass it your data.
At last, I am able to solve the issue, many thanks to the answer. Here is the detailed explanation for beginners like me:
This is the source controller class, which is a tabbar controller and it transfers the data:
class SourceTC: UITabBarController {
var dataTransferFrom = "transfer this string"
override func viewDidLoad() {
super.viewDidLoad()
let finalVC = self.viewControllers![0] as! DestinationVC //first view controller in the tabbar
finalVC.dataTransferTo = dataTransferFrom
}
}
and this is the destination controller class, which is a view controller under tabbar controller and it gets the transferred data:
class DestinationVC: UIViewController {
var dataTransferTo = ""
override func viewDidLoad() {
super.viewDidLoad()
print(dataTransferTo)
}
}
Related
So, I want to prefetch some of the data needed in the view controllers associated with the tab bar controller as the user moves from the login page to the home page (tab bar controller exists between these two view controllers). I'm fetching the data in a custom TabBarController class and using the following code to send it (doesn't work):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is Profile { // Profile = one of the view controllers in the tab bar
let vc = segue.destination as? Profile
vc?.uid = self.userID
vc?.name = self.name
vc?.skills = self.skillSet
}
}
What is the best way to do this? Please note I can't prefetch the data before the tab bar controller as that is the login page. If I prefetch the profile page data on the home page (tab bar controller {home, search, profile}), how can I transfer it to another view controller (to profile) in the same tab bar?
What is the best way to do this?
I believe once you perform login call (Inside login screen) you will have userID and other data related to that user, so inside Login controller you have added code for making Tabbar controller as initial controller.
So based on that best thing is to store userData into tabbar controller.
So once you sore data into tabbar controller (from either login or Home Screen) you can fetch user data in any root controller (home, search, profile) which is inside tab-bar by below code.
struct User { var userID: String? }
class TabbarController: UITabBarController {
var userData: User
}
class HomeController: UIViewController {
var userData: User?
override func viewWillAppear(_ animated: Bool) {
if let tabBar = self.tabBarController as? TabbarController {
self.userData = tabBar.userData
}
}
}
There are multiple ways you can achieve this.
Using SuperViewController,
Using SingleTone class if you want to access in other than TabbarViewVontroller subclass.
Saving in a common location like in constants if data is small.
Prefetching data in one VC e.g Home and then passing to the required VC on click.
I have a TableViewController and 2 ways to get there.
one is a segue(show) from a Viewcontroller that is the root controller of a Navigation Controller, which itself is a tab of my Tab Bar Controller.
second, the tableVC is also a root VC of antoher Navigation Controller, that is also a tab in that Tab Bar Controller. Here is an illustration:
Now i want to check in the viewDidLoad if my TableVC, whether it is called by the first or by the second way. How can i find that out?
You could add a property to your view controller that indicates where it came from…
class MyTableViewController: UITableViewController {
enum Source {
case productList, basket
}
var source: Source!
}
then
override func prepareForSegue(segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? MyTableViewController {
vc.source = .productList
}
}
etc
very simple just add a var on your viewController which you are going to display , lets assume var vcOpenedBy = ""
now when launching this ViewController , just use this var and print whatever you feel comfortable like this
let vc = VcController(nibName:"",bundle:nil)
vc.vcOpenedBy = "NavigationMethod"
and at your segue you can also use this vcOpenedBy
and use string "SqgueMethod"
now on that viewController in viewDidLoad()
just print this vc . thats it
I have Table View Controller, intended to serve as a settings page, that contains a UISegmentedControl with 3 segments:
class SettingsView: UITableViewController {
#IBOutlet weak var ButtonSelection: UISegmentedControl!
//Index 0 is default selection (first)
override func viewDidLoad() {
super.viewDidLoad()
// some code
}
Separately, I have a Navigation View Controller that controls 3 different UIViewControllers with corresponding Storyboard IDs ("first", "second", and "third").
I'm trying to prepare the Navigation View Controller to present the appropriate View Controller based on UISegmentedControl selection. However, I keep getting "fatal error: unexpectedly found nil while unwrapping an Optional value" and not sure how to resolve.
This is what I have tried:
class NavViewController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
if SettingsView().ButtonSelection.selectedSegmentIndex == 0 {
print ("first segment is selected")
let destinationController = storyboard?.instantiateViewController(withIdentifier: "first")
else if SettingsView().ButtonSelection.selectedSegmentIndex == 1 {
print ("second segment is selected")
let destinationController = storyboard?.instantiateViewController(withIdentifier: "second")
else if SettingsView().ButtonSelection.selectedSegmentIndex == 0 {
print ("third segment is selected")
let destinationController = storyboard?.instantiateViewController(withIdentifier: "third")
Could anyone point me in the right direction, please? Thanks in advance!
You have a couple of problems.
Problem 1: A UITableViewController is not set up to host anything but a table view. It's content view is locked to be a table view. If you want a table view that's managed by a UITableViewController and you want other content in the view controller, you need to make the UITableViewController a child of another view controller. The good news is that that is trivially easy using a container view and an embed segue.
Problem 2 is a "don't do that" problem. You should treat a view controller's views as private. Another view controller should not try to look at or change another view controller's segmented control. (It's bad design, and it also can lead to crashes like the one you describe because you can't be sure if the other view controller's views have been loaded yet.) Instead, you should add an integer property "selectedIndex" to the view controller that contains the segmented control, and use that to read/write the selected segment. (In OOP terms, you add a public interface to your view controller's "contract" that exposes the features you want to expose, and then add code that provides that interface.)
I want to change the navigation's title of a view, which is related to a Tab Bar Controller, which is related to a Navigation Controller (see the picture)
I don't know how to do that.
With a basic view, I just need to do that in the ViewController.swift :self.title="test"
But here, this line changed the tab bar's title, but I want to change the navigation's title.
Main.Storyboard :
On Swift 3, in the UIViewController, override your viewDidAppear method and add this code snippet:
if let tabController = self.parent as? UITabBarController {
tabController.navigationItem.title = "My Title"
}
Use need to use this property:
self.navigationItem.title = "someTitle"
According to Apple best practices you should not have a tab bar controller contained inside of a navigation controller, rather you should have the view controller for each tab that requires one to be inside of it's own navigation controller.
There are various issues that can arise from having a tab bar controller contained within a navigation controller.
When implemented according to their standards you can set the title using self.title
An app that uses a tab bar controller can also use navigation controllers in one or more tabs. When combining these two types of view controller in the same user interface, the tab bar controller always acts as the wrapper for the navigation controllers.
https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/CombiningViewControllers.html
Embed UINavigationController in your storyboard and put:
navigationBar.topItem.title = "Nav title"
I also had difficulty to change a navigation bar title of a child view controller. The solution was:
#IBOutlet weak var navigationBar: UINavigationBar!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationBar.topItem!.title = "Pickup Address"
}
For Swift 3+
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.title = "Title"
}
At my storyboard I have a part where a view controller with a table view is placed before a tab bar controller. This tab bar has two view controllers. Earlier I used the table view already, and when I clicked on one cell I passed to another Viewcontroller which loaded another view controller with table and cells with the id from the pushed cell from the first table. Like this:
The tableview controller, prepare for segue:
if segue.identifier == "overviewSegue" {
var caseViewController: CaseViewController = segue.destinationViewController as CaseViewController
var caseIndex = overviewTableView!.indexPathForSelectedRow()!.row
var selectedCase = self.cases[caseIndex]
caseViewController.caseitem = selectedCase
}
This works well. Now I want to do the same, but the only difference is that the last view controller is part of a tabbar controller. The problem is I can't get it working to pass the data to this last table view controller.
I tried several things, but I can't point the data to the tabbar table view. Segue's are not approachable, and the destination isn't the table view controller, but the tabbar controller, etc. The question, how to pass data from a tableview through the tabbar controller to another view controller.
I have found a solution:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toTabController" {
var tabBarC : UITabBarController = segue.destinationViewController as UITabBarController
var desView: CaseViewController = tabBarC.viewControllers?.first as CaseViewController
var caseIndex = overviewTableView!.indexPathForSelectedRow()!.row
var selectedCase = self.cases[caseIndex]
desView.caseitem = selectedCase
}
}
Easy explanation: You need to get to your Tab bar controller and pick his view controllers. It normally has two, so you can pick the first. After that, define which class it belongs to, and you can pass your data just as you did before.