Controlling Nav Controller from another - ios

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.

Related

Using functions from delegate in SwiftUIView

Quick question for anyone feeling up for helping a noob.
So I have a protocol in my main class that has a function that I'd like to access from a UIView. This works for other view controllers. However, in my prepare function, I try this:
if let destination = segue.destination as? SwiftUIView {
destination.delegate = self
}
But I get, "Cast from 'UIViewController' to unrelated type 'SwiftUIView' always fails"
and "Cannot assign to property: 'destination' is a 'let' constant".
This is my whole prepare function:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.destination is ClientView
{
let vc = segue.destination as? ClientView
vc?.username = thetitle;
}
if let destination = segue.destination as? CreateClientView {
destination.delegate = self
}
if let destination = segue.destination as? SwiftUIView {
destination.delegate = self
}
}
and it works in the CreateClientView. But not for my SwiftUIView. Any idea how to fix this? I am accessing the function in SwiftUIView the same way I do in CreateClientView. Thanks everybody.
SwiftUIView is just type View and looks like this (abridged):
struct SwiftUIView: View {
#State var username: String = ""
#State var address: String = "";
#State var notificationsEnabled: Bool = false
#State var note: String = "";
var delegate:ClientDelegate?;
and SwiftUIView is a child of another view which looks like this:
class CreateClientView: UIViewController {
let contentView = UIHostingController(rootView: SwiftUIView());
var delegate:ClientDelegate?;
var mainView : ViewController?;
override func viewDidLoad() {
super.viewDidLoad()
addChild(contentView);
view.addSubview(contentView.view);
setupConstraints()
// Do any additional setup after loading the view.
}
As the error message states, you're trying to cast a SwiftUI view into a ViewController. which you cant.
For a quick fix to your problem you can try this
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.destination is ClientView
{
let vc = segue.destination as? ClientView
vc?.username = thetitle;
}
if let destination = segue.destination as? CreateClientView {
destination.delegate = self
}
if let destination = segue.destination as? CreateClientView {
destination.delegate = self
}
}
class CreateClientView: UIViewController, SwiftUIViewDelegate {
let contentView = UIHostingController(rootView: SwiftUIView(delegate: self));
var delegate:ClientDelegate?;
var mainView : ViewController?;
override func viewDidLoad() {
super.viewDidLoad()
addChild(contentView);
view.addSubview(contentView.view);
setupConstraints()
// Do any additional setup after loading the view.
}
// MARK: SwiftUIViewDelegate
// call ClientDelegate here whereever SwiftUIViewDelegate methods are implemeted
}
protocol SwiftUIViewDelegate {...}
struct SwiftUIView {
let delegate: SwiftUIViewDelegate
}

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
}

Pass Information through TabBarController Swift

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"
}

Could not cast value of type 'Authorize.ClubsViewController' (0x109c70cc8) to 'Authorize.NewViewController' (0x109c70df8)

#IBOutlet weak var menuButton: UIButton!
#IBOutlet weak var clubButton: UIButton!
#IBOutlet weak var announcemnetsButton: UIButton!
#IBOutlet weak var eventButton: UIButton!
let transition = CircularTransition()
override func viewDidLoad() {
super.viewDidLoad()
menuButton.layer.cornerRadius = menuButton.frame.size.width / 2
clubButton.layer.cornerRadius = menuButton.frame.size.width / 2
announcemnetsButton.layer.cornerRadius = menuButton.frame.size.width / 2
eventButton.layer.cornerRadius = menuButton.frame.size.width / 2
// Do any additional setup after loading the view.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let secondVC = segue.destination as! NewViewController
secondVC.transitioningDelegate = self
secondVC.modalPresentationStyle = .custom
let thirdVC = segue.destination as! ClubsViewController
thirdVC.transitioningDelegate = self
thirdVC.modalPresentationStyle = .custom
let fourthVC = segue.destination as! AnnouncementsViewController
fourthVC.transitioningDelegate = self
fourthVC.modalPresentationStyle = .custom
let fifthVC = segue.destination as! EventsViewController
fifthVC.transitioningDelegate = self
fifthVC.modalPresentationStyle = .custom
}
I am running this code but I keep getting the error, what am I doing wrong? I believe everything is linked correctly, but I keep getting the SIGABRT error.
Every Segue has a identifier. You have to set identifier for segue
In the prepare you are not checking the segue identifier. Due to that you are trying to forcefully convert the segue.destination controller four different controller, which is wrong.
Please see how to set segue identifier
And change your code based on your segue identifier
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "NewVC" {
let secondVC = segue.destination as! NewViewController
secondVC.transitioningDelegate = self
secondVC.modalPresentationStyle = .custom
} else if segue.identifier == "ClubVC" {
let thirdVC = segue.destination as! ClubsViewController
thirdVC.transitioningDelegate = self
thirdVC.modalPresentationStyle = .custom
} else if segue.identifier == "AnnouncementVC" {
let fourthVC = segue.destination as! AnnouncementsViewController
fourthVC.transitioningDelegate = self
fourthVC.modalPresentationStyle = .custom
} else if segue.identifier == "EventVC" {
let fifthVC = segue.destination as! EventsViewController
fifthVC.transitioningDelegate = self
fifthVC.modalPresentationStyle = .custom
}
}
You seem to be converting the same segue destination to many different types of VC which it obviously cannot be all at the same time.
I think what you intended to do is to check if the segue destination is of the specific type (in which case you must not force-unwrap with !):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondVC = segue.destination as? NewViewController {
secondVC.transitioningDelegate = self
secondVC.modalPresentationStyle = .custom
} else if let thirdVC = segue.destination as? ClubsViewController {
thirdVC.transitioningDelegate = self
thirdVC.modalPresentationStyle = .custom
} else if let fourthVC = segue.destination as? AnnouncementsViewController {
fourthVC.transitioningDelegate = self
fourthVC.modalPresentationStyle = .custom
} else if let fifthVC = segue.destination as? EventsViewController {
fifthVC.transitioningDelegate = self
fifthVC.modalPresentationStyle = .custom
}
}
Using segue identifiers though could be more sensible in this situation.
Then again, considering that you are always performing the same actions no matter what VC that is, maybe it's worth casting it to a generic VC (i.e. as! UIViewController and performing an action on that instead of differentiating them?

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"
}
}
}

Resources