Swift: Pass data from a view controller to a navigation controller - swift

I want to pass data from a view controller to another but I've a Navigation controller between them, so there's a "present" function instead a "performSegue".
private func IniciarMainAdmin(){
let mainAdmin = UIStoryboard(name: "Main", bundle: Bundle.main)
guard let mainAdminNVC = mainAdmin.instantiateViewController(withIdentifier: "NCMainAdmin") as? NCMainAdmin else{
return
}
present(mainAdminNVC, animated: true, completion: nil)
}
I've tried with this code but it didn't work for me:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destViewController = segue.destination as! NCMainAdmin
let secondViewcontroller = destViewController.viewControllers.first as! NCMenuAdmin
secondViewcontroller.adminUserData = "This is a test"
}
Notes:
NCMainAdmin is the Navigation Controller
NCMenuAdmin is the first View Controller of the Navigation Controller
Thanks!

For your code prepare(for to trigger , you need to create a segue from the sender vc to the navigation , so either
private func IniciarMainAdmin(){
let mainAdmin = UIStoryboard(name: "Main", bundle: Bundle.main)
guard let mainAdminNVC = mainAdmin.instantiateViewController(withIdentifier: "NCMainAdmin") as? NCMainAdmin else{
return
}
let first = mainAdminNVC.viewControllers.first as! NCMenuAdmin
first.adminUserData = "This is a test"
present(mainAdminNVC, animated: true, completion: nil)
}
OR
self.performSegue(withIdentifier:"id",sender:nil)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destViewController = segue.destination as! NCMainAdmin
let secondViewcontroller = destViewController.viewControllers.first as! NCMenuAdmin
secondViewcontroller.adminUserData = "This is a test"
}

Related

if let editItemVC = segue.destination as? ItemDetailViewController {} doesn't work

i have two segues in this tableViewController, but the downcasting in prepare(for: segue) doesn't work.
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
print("into segue")
super.prepare(for: segue, sender: sender)
switch segue.identifier {
case "addItem":
print("addItem Segue")
if let addItemVC = segue.destination as? ItemDetailViewController {
print("if let done")
addItemVC.container = container
} else {
print("WTF")
}
case "editItem":
print("editItem Segue")
if let editItemVC = segue.destination as? ItemDetailViewController {
guard let selectedItemCell = sender as? PriorityListTVCell else {
fatalError("Unexpected sender: \(String(describing: sender))")
}
guard let indexPath = tableView.indexPath(for: selectedItemCell) else {
fatalError("The selected cell is not being displayed by the table")
}
editItemVC.editedInfo = list[indexPath.row]
print("passed indexPath.row: \(indexPath.row)")
editItemVC.container = container
}
default:
break
}
}
if i click "add" button, in the console it'll print out
into segue
addItem Segue
WTF
not sure why the downcasting doesn't work, does it have anything to do with segue types of destination?
Thanks for help!
This
if let addItemVC = segue.destination as? ItemDetailViewController {
won't work if the destination vc isn't of type ItemDetailViewController meaning you need to assign the class name in IB , for help you can do
print(type(of:segue.destination))
For navigation do
if let nav = segue.destination as? UINavigationController ,
let addItemVC = nav.viewControllers?.first as? ItemDetailViewController {}

Prepare For Segue on return

So the code I am trying to implement in Swift is based upon this answer here for passing data back from a ViewController:
Passing Data with a Callback
Now my issue is after I have called:
self.navigationController?.popViewController(animated: true)
The Prepare For Segue function isn't called in my original View Controller. I assume it shouldn't be called anyway but from that answer I assume there is a possible way to do so?
First View Controller Snippets
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//ignore this segue identifier here, this function works when I am showing a new VC
if(segue.identifier == "certSegue"){
let certVC = segue.destination as! CertificateViewController
certVC.profileModel = profileModel
}
//this is what I need to be called
if(segue.identifier == "dpSegue"){
print("dpSegue")
let dpVC = segue.destination as! DatePickerViewController
dpVC.callback = { result in
print(result)
print("Data")
// do something with the result
}
//dpVC.dailyBudgetPassedThrough = "Test"
}
}
func showDatePicker(){
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "DatePickerVC") as? DatePickerViewController
self.navigationController?.pushViewController(vc!, animated: true)
}
Second View Controller
import UIKit
class DatePickerViewController: UIViewController {
var callback : ((String)->())?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func sendBackUpdate(){
print("Callback")
callback?("Test")
}
#IBAction func cancelButton(_ sender: Any) {
self.navigationController?.popViewController(animated: true)
}
#IBAction func updateButton(_ sender: Any) {
sendBackUpdate()
self.navigationController?.popViewController(animated: true)
}
}
prepareForSegue is called if in Interface Builder a segue is connected
from a table/collection view cell to a destination view controller and the cell is tapped.
from a source view controller to a destination view controller and performSegue(withIdentifier:sender:) is called in the source view controller.
It's not called when a view controller is going to be presented with pushViewController
In your case assign the callback after instantiating the controller in showDatePicker, prepare(for segue is not needed.
func showDatePicker(){
let vc = UIStoryboard(name: "Main", bundle: .main).instantiateViewController(withIdentifier: "DatePickerVC") as! DatePickerViewController
vc.callback = { result in
print(result)
print("Data")
// do something with the result
}
self.navigationController?.pushViewController(vc, animated: true)
}

Swift: Can't push to view controller programatically

I'm trying to push to different viewcontroller programatically using this code:
let loginVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginViewController") as! MenuController
self.navigationController?.pushViewController(loginVC, animated: true)
Here is my setup: I have swift file called: MenuController which contains this code I set the identifier name to: LoginViewController I set the class of both ViewControllers set to MenuController. But whenever I press the button to trigger the event it doesn't do anything.
Here is the rest of my code as requested:
import UIKit
class MenuController: UIViewController {
var thingy = 0
#IBAction func ThingyBttn(_ sender: UIButton) {
if(thingy == 1) {
print("ok")
}else{
print("good")
let loginVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginViewController") as! MenuController
self.navigationController?.pushViewController(loginVC, animated: true)
}
}
#IBOutlet var myButton: UIButton!
#IBAction func Button(_ sender: UIButton) {
if let ButtonImage = myButton.image(for: .normal),
let Image = UIImage(named: "ButtonAppuyer.png"),
UIImagePNGRepresentation(ButtonImage) == UIImagePNGRepresentation(Image) {
thingy = 1
print("1")
} else {
thingy = 2
print("2")
}
}
}
I know that everything else with the code works fine because it's printing the message.
You need to insert the vc you do the push from inside a navigationController as this
self.navigationController?
is nil , or do it programmatically
Edit:
Replace this
let loginVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginViewController") as! MenuController
self.navigationController?.pushViewController(loginVC, animated: true)
with
let loginVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginViewController") as! MenuController
let nav = UINavigationController(rootViewController:self)
(UIApplication.shared.delegate as! AppDelegate).window!.rootViewController = nav
nav.pushViewController(loginVC, animated: true)
I think your view controllers are not in Navigation Stack thats why its not pushing to next view controller
let nextVC = self.storyboard?.instantiateViewController(withIdentifier: “nextvc”) as! nextvc
let navigation = UINavigationController(rootViewController:self)
UIAppliaction.window!.rootViewController = navigation
navigation.pushViewController(nextVC, animated: true)

SWReveal TableViewController - how to launch to different ViewControllers?

I'm using the SWReveal slide out menuing system.
The menu is generated from an array, and all works fine. E.g.
arrayOfCellData = [cellData(cell : 1, text : "Angles", image : #imageLiteral(resourceName: "Angles.png")),
cellData(cell : 2, text : "Area", image : #imageLiteral(resourceName: "Area.png")),
When I tap on a particular menu option I want to segue to a different ViewController. Here is the code that I have been using which doesn't work.
The idea that Row 1 invokes segue A and 2 segue B...
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if(indexPath.row == 1 ){
let vc: AnyObject! = self.storyboard?.instantiateViewController(withIdentifier: "A")
self.performSegue(withIdentifier: "A", sender: self)
self.show(vc as! A, sender: vc)
NSLog("A")
}
if(indexPath.row == 2 ){
let vc: AnyObject! = self.storyboard?.instantiateViewController(withIdentifier: "B")
self.performSegue(withIdentifier: "B", sender: self)
self.show(vc as! B, sender: vc)
NSLog("B")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let backItem = UIBarButtonItem()
backItem.title = " "
navigationItem.backBarButtonItem = backItem
if segue.identifier == "A", let nextScene = segue.destination as? A {
nextScene.categoryCounter = 1
}
if segue.identifier == "B", let nextScene = segue.destination as? B {
nextScene.categoryCounter = 2
}
}
With SWRevealViewController it is best to not use segues in storyboard and instead contract your reveal view controller programmatically. Try this, in your didSelectRowAtIndexPath method add the following to your code.
// Here I get the view controllers I am interested in
let frontStoryboard = UIStoryboard(name: "YourStoryboard", bundle: .main)
let frontVC = frontStoryboard.instantiateInitialViewController()
let rearStoryboard = UIStoryboard(name: "YourOtherStoryboard", bundle: .main)
let rearVC = rearStoryboard.instantiateInitialViewController()
// Construct the SWRevealViewController with your view controllers
if let revealVC = SWRevealViewController(rearViewController: rearVC, frontViewController: frontVC) {
revealVC.modalTransitionStyle = .crossDissolve // Set segue transition
present(revealVC, animated: true, completion: nil) // Segue to view controller
}

Segue and Button programmatically swift

I am using iCarousel and I have to create my own button. I want to pass data from the button made programmatically to another view, but I don't have a segue identifier because I created the button programmatically. I don't know if it is possible to create the identifier of the segue programmatically.
button.addTarget(self, action: #selector(buttonAction3), for: .touchUpInside)
button.setTitle("\(titulos[index])", for: .normal)
tempView.addSubview(button)
let myImage = UIImage(named: "modo4.png") as UIImage?
button.setImage(myImage, for: .normal)
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "modo") as! Modo1ViewController
self.present(viewController, animated: false, completion: nil)
if segue.identifier == "" {
if let destination = segue.destination as? Modo1ViewController {
destination.nomb = nombres
}
}
Create seuge
Assign identifier
and your button target
#IBAction func button_clicked(_ sender: UIButton) {
self.performSegue(withIdentifier: "segueToNext", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueToNext" {
if let destination = segue.destination as? Modo1ViewController {
destination.nomb = nombres // you can pass value to destination view controller
// destination.nomb = arrayNombers[(sender as! UIButton).tag] // Using button Tag
}
}
}
in your case, if you use self.present and you want to send data between views. Try this:
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "modo") as! Modo1ViewController
viewController.nomb = nombres
self.present(viewController, animated: false, completion: nil)
I don't know how to set segue's identifier but I think code above can help
If you want do to easier work, you can create segue in IB (Interface Builder) and set it's identifier, then use
performSegue:withIdentifier:sender