Pass Information through TabBarController Swift - ios

Have a Table View Controller that will pass an ID field onto a View Controller in order to retrieve detail however in between the two controllers is a Tab Bar Controller. I am unsure how I am to get the information passed between the two. Was attempting to use a Segue but the value is blank once it gets to the detail controller.
EventBarTableViewCell.swift
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showEventDetail" {
if let IndexPath = self.tableView.indexPathForSelectedRow {
let controller = segue.destination as? eventDetailViewController
controller?.inTradeShowID = (events?[IndexPath.row].tradeshowID!)!
controller?.viaSegue = (events?[IndexPath.row].tradeshowID!)!
//controller?.performSegue(withIdentifier: "tradeShowID", sender: self)
//if shouldShowSearchResults {
// controller?.viaSegue = filteredArray[IndexPath.row].charterNum!
//} else {
// controller?.viaSegue = repositories[IndexPath.row].charterNum!
//}
}
}
}
eventDetailViewController.swift
var viaSegue = ""
var inTradeShowID = ""
override func viewDidLoad() {
super.viewDidLoad()
inTradeShowID = self.viaSegue
}
Could use some help.

You are segueing to a Tab Bar Controller, not to your "display" view, so you need to "drill down" so to speak:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showEventDetail" {
if let IndexPath = self.tableView.indexPathForSelectedRow {
// we're segueing to a Tab Bar Controller
if let tabBarVC = segue.destination as? UITabBarController {
// get the first view controller of the Tab Bar Controller
// *that* is where you want to "pass" your data
if let controller = tabBarVC.viewControllers?.first as? eventDetailViewController {
// either should work
controller.inTradeShowID = (events?[IndexPath.row].tradeshowID!)!
controller.viaSegue = (events?[IndexPath.row].tradeshowID!)!
} //end if let controller = tabBarVC.viewControllers?.first as? eventDetailViewController
} //end if let tabBarVC = segue.destination as? UITabBarController
} //end if let IndexPath = self.tableView.indexPathForSelectedRow
} //end if segue.identifier == "showEventDetail"
}

Related

Passing data forward from ViewController to ContainerView

I am using network request to retrieve data from back-end in ViewController and this view contains three containers so, I want to pass these data into containers. that fails while I am using prepare for segue.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ContinueSurvey" {
let continueSurveyVC = segue.destination as! ContinueSurveyVC
continueSurveyVC.notComplatedSurveies = notComplatedSurveies
} else if segue.identifier == "LatestOffers" {
let latestOffersVC = segue.destination as! LatestOffersVC
latestOffersVC.latestOffers = latestOffers
} else if segue.identifier == "LatestSurvey" {
let latestSurveyVC = segue.destination as! LatestSurveyVC
latestSurveyVC.latestSurveies = latestSurveies
}
}
This might help: https://learnappmaking.com/pass-data-between-view-controllers-swift-how-to/
Here’s a view controller MainViewController with a property called
text:
class MainViewController: UIViewController
{
var text:String = ""
override func viewDidLoad()
{
super.viewDidLoad()
}
}
Whenever you create an instance of MainViewController, you can assign
a value to the text property. Like this:
let vc = MainViewController()
vc.text = "Hammock lomo literally microdosing street art pour-over"
This is the code for the view controller:
class SecondaryViewController: UIViewController
{
var text:String = ""
#IBOutlet weak var textLabel:UILabel?
override func viewDidLoad()
{
super.viewDidLoad()
textLabel?.text = text
}
}
Then, here’s the actual passing of the data… Add the following method
to MainViewController:
#IBAction func onButtonTap()
{
let vc = SecondaryViewController(nibName: "SecondaryViewController", bundle: nil)
vc.text = "Next level blog photo booth, tousled authentic tote bag kogi"
navigationController?.pushViewController(vc, animated: true)
}
you can use present ViewController and in presented ViewController in viewWillAppear check what happened:
present VeiwController:
let vc = self.storyboard?.instantiateViewController(withIdentifier: "yourViewControllerIdentifire") as! yourViewController
self.present(vc, animated: true, completion: nil)
& in yourViewContriller use viewWillAppear to pass those data into containers:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//pass those data into containers
}
If you want to update child controllers when they already loaded, you need to store reference on them in parent controller and then in desire moment of time update data as:
weak var continueSurveyVC: ContinueSurveyVC?
weak var latestOffersVC: LatestOffersVC?
weak var latestSurveyVC: LatestSurveyVC?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ContinueSurvey" {
continueSurveyVC = segue.destination as! ContinueSurveyVC
continueSurveyVC?.notComplatedSurveies = notComplatedSurveies
} else if segue.identifier == "LatestOffers" {
latestOffersVC = segue.destination as! LatestOffersVC
latestOffersVC?.latestOffers = latestOffers
} else if segue.identifier == "LatestSurvey" {
latestSurveyVC = segue.destination as! LatestSurveyVC
latestSurveyVC?.latestSurveies = latestSurveies
}
}
/// Call this method anytime you want to update children data
func updateChildData() {
continueSurveyVC?.notComplatedSurveies = notComplatedSurveies
latestOffersVC?.latestOffers = latestOffers
latestSurveyVC?.latestSurveies = latestSurveies
}

Controlling Nav Controller from another

My view controllers are sitting inside of view containers.
I'm trying to change the nav controller in the green area with the buttons from the purple area.
In my Main View controller I have:
class MainViewController: UIViewController,Purpleprotocol,Greenprotocol {
weak var infoNav : UINavigationController?
weak var greenVC: GreenVC?
weak var purpleVC: PurpleVC?
weak var peachVC: PeachVC?
func changenav(whichbutton: String) {
print ("changenav")
print(whichbutton + "whichbuttonstring")
if(whichbutton == "1"){
print("change one")
let svc = storyboard?.instantiateViewController(withIdentifier: "rootController") as! GreenVC
self.infoNav?.pushViewController(svc, animated: true)
}
if(whichbutton == "2"){
print("change two")
let svc = storyboard?.instantiateViewController(withIdentifier: "secondController") as! SecondViewController
self.infoNav?.pushViewController(svc, animated: true)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "contentSegue" {
print("contentSegue")
let infoNav = segue.destination as! UINavigationController
let greenVC = infoNav.viewControllers[0] as! GreenVC
greenVC.delegate = self
}
if segue.identifier == "menuSegue" {
let dvmenu = segue.destination as! PurpleVC
purpleVC = dvmenu
dvmenu.delegate = self
}
}
This function does work and I can see the "change one" etc being called but the navigation controller is just not changing..not sure how to get to it I guess correctly.

Pass Data From One TabbarVC to Another TabbarVC W/O losing Tabbar

I want to pass photo data from one Viewcontroller(cameraVC) in a Tabbarcontroller to another Viewcontroller(mainVC) in the same Tabbarcontroller without losing the tabbar after I perform the segue.
Setup:
*Tabbarcontroller
-Navbarcontroller
--mainVC (Tabbar Item)
--cameraVC (Tabbar Item)
I must be able to use prepareForSegue and performSegue in cameraVC (This is how I am passing the data over to mainVC).
What I have tried W/O success:
Keeping tab bar on View after segue?,
Why TabBar hides after the segue?
current implementation:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationNavigationController = segue.destination as! UINavigationController
let targetController = destinationNavigationController.topViewController as! HomeVC
// if let homeVC = segue.destination as? HomeVC {
if let imageDict = sender as? Dictionary<String, Any> {
let imageData = imageDict["snapshotData"]
targetController.imageData = imageData as? Data
// }
}
}
#IBAction func sendBtnPressed(_ sender: Any) {
performSegue(withIdentifier: "goFeed", sender: ["snapshotData": photoData.removeValue(forKey: "photoData")])
imageTaken.image = nil
self.view.insertSubview(previewView, aboveSubview: imageView)
}
You are using the sender argument of the performSegue(_:, sender:) method incorrectly. It should be the view controller initiating the segue. It looks like your photoData property belongs to the view controller initiating the segue, so just access it directly in the prepareForSegue method. So it would look like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationNavigationController = segue.destination as! UINavigationController
let targetController = destinationNavigationController.topViewController as! HomeVC
if let imageData: Data = self.photoData["photoData"] as? Data {
targetController.imageData = imageData
}
}
#IBAction func sendBtnPressed(_ sender: Any) {
performSegue(withIdentifier: "goFeed", sender: self)
imageTaken.image = nil
self.view.insertSubview(previewView, aboveSubview: imageView)
}
The way I solved the problem was by creating a variable in my TabbarController which is globally recognized and used to pass the image data to the mainVC. This was the most viable solution for me to avoid creating duplicate views.

Pass text to TextView via Segue

I'm trying to pass text to TextView from other ViewController:
if (segue.identifier == "HomeToDetails") {
let nav = segue.destination as! UINavigationController
let nextVC = nav.topViewController as! DetailsViewController
nextVC.infoTextView.text = "TESTING"
}
But it crashes:
fatal error: unexpectedly found nil while unwrapping an Optional value
setting text on UITextField of DestinationViewController is not possible in the prepareForSegue:sender, because all view components of the recently allocated controller are not initialized before the view is loaded (at this time, they are all nil), they only will be when the DestinationViewController view is loaded.
You need to use optional variable infoString in DetailsViewController which you can set in prepareForSegue method
if (segue.identifier == "HomeToDetails") {
let nav = segue.destination as! UINavigationController
let nextVC = nav.topViewController as! DetailsViewController
nextVC.infoString = "TESTING"
}
in DetailsViewController.swift
class DetailViewController: UIViewController {
var infoString: String?
override func viewDidLoad() {
super.viewDidLoad()
if let info = infoString {
self.infoTextView.text = info
}
}
}
if value is nil and you unwrap it, then the app will crash, you should use optional binding to avoid crash.
if (segue.identifier == "HomeToDetails") {
if let nav = segue.destination as? UINavigationController { //should use optional binding to avoid crash
if let nextVC = nav.topViewController as? DetailsViewController {
nextVC.infoTextView.text = "TESTING"
}
}
}
Check this:
if (segue.identifier == "HomeToDetails") {
// get a reference to the second view controller
let secondViewController = segue.destination as! DetailsViewController
// set a variable in the second view controller with the String to pass
secondViewController.infoTextView.text = "TESTING"
}
Try this code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let nav = segue.destination as? UINavigationController {
if let nextVC = nav.topViewController as? DetailsViewController {
nextVC.infoTextView.text = "Data you want to pass"
}
}
}
this is because when you are assigning value to text view, the text view not initialized that time as viewDidLoad of next class is not called yet. So pass only string, then in viewDidLoad of next class, set the text.
You cannot pass a text directly to TextView in another view before it's created.
First ViewController:
if (segue.identifier == "HomeToDetails") {
let secondViewController = segue.destination as! DetailsViewController
secondViewController.myText = "TESTING"
}
DetailsViewController:
var myText = ""
override func viewDidLoad() {
super.viewDidLoad()
infoTextView.text = myText
}
All view components of the DetailsViewController are not initialized before the view is loaded. You can load that view before assigning values to the components of that view
Consider vC is the view controller which contains the view that you want to load. Then
if let _ = vC.view {
//Assign value here
}
Once the view is loaded, we can set the value to the components in that view. In SWIFT 3
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "HomeToDetails" {
let nav = segue.destination as! UINavigationController
let nextVC = nav.topViewController as! DetailsViewController
if let _ = nextVC.view {
nextVC.infoTextView.text = "TESTING"
}
}
}

Passing Core Data objects from DetailViewController to another View Controller

Is there a way to pass Core Data objects from DetailViewController to another View Controller to allow Editing?
From MasterViewController navigate to DetailViewController:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let myValue = myValues[indexPath.row]
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = myValue
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
}
Then From DetailViewController to EditViewController:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showEdit" {
let controller = editViewController
controller.editItem = detailItem
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
But i get nil on my object
EDIT
The edit Item is set like this on EditViewController:
var editItem: MyValues? {
didSet {
// Update the view.
self.configureView()
}
}
and the detailItem is set like this in DetailViewController:
var detailItem: MyValues? {
didSet {
// Update the view.
self.configureView()
}
}
Instead of using a property for the edit controller, use what you get from the segue.
I.e. (Assuming you're moving directly to your EditViewController): Replace...
let controller = editViewController
...with something like...
let controller = segue.destinationViewController as! EditViewController
...except you should probably test it rather than using as!.
===
Updating with my guess about how this came to be. (See comments.)
You must have created whatever editViewController points to in code someplace, which means it's not the same instance/object that is created for you as part of the segue mechanism. In other words, you had two different EditViewController objects and you were not passing data to the one that was going to be putting views on the screen.

Resources