How to pass information back with view controllers - ios

I have a view controller and one table View Controller. I go from VC One to VCTable. On VCTable, I select a(cell) data from type string that I store in value. When I press a cell, I would like to send that data back to VC One.
and show in button or label.
How to do this using Storyboards?

you should take a look at protocols / delegation:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html

First Solution: Using CallBack
In your VCOne:
#IBAction func goToViewController2(sender: AnyObject) {
let vc2 = storyboard?.instantiateViewControllerWithIdentifier("ViewController2") as! ViewController2
vc2.callback = ({ string in
self.myString = string
})
presentViewController(vc2, animated: true, completion: nil)
}
in your VCTable:
create a callback variable:
var callback: ((String) -> Void)?
in your didSelectRowAtIndexPath method, send it to VCOne by:
callback?(textField.text!)
Second Solution: Using Reference
#IBAction func goToViewController2(sender: AnyObject) {
let vc2 = storyboard?.instantiateViewControllerWithIdentifier("ViewController2") as! ViewController2
vc2.vc1 = self
presentViewController(vc2, animated: true, completion: nil)
}
in your VCTable:
create this variable:
var vc1: ViewController?
in your didSelectRowAtIndexPath method, send it to VCOne by:
vc1?.myString = textField.text!
Third Solution: Using Delegate see the link as #Andre Slotta said.
FourthSolution: Using CenterNotification Googling for this :).
Hope this help :)

Related

passing data from 2 view controllers without segue

I have a mainviewcontroller and a popup view controller which opens without a segue.
the popup viewcontroller recive data from Firebase, and then i need to append this data to an array in the mainviewcontroller.
How can i do that?
(i tried to create a property of the popupviewcontroller in the mainviewcontroller, but in crashes the app)
this is the code that opens the popup:
#IBAction func showPopUp(_ sender: Any) {
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbPopUp") as! PopUpViewController
self.addChild(popOverVC)
popOverVC.view.frame = self.view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParent: self)
You need to connect the classes so that the popup class knows what to do with the data once it has been received. Here's a sample structure that works in a playground that you should be able to apply to your real classes.
class MainClass {
func showPopUp() {
let popOverVC = PopUpClass()
popOverVC.update = addToArray
popOverVC.receivedData()
}
func addToArray() {
print("Adding")
}
}
class PopUpClass {
var update: (()->())?
func receivedData() {
if let updateFunction = update {
updateFunction()
}
}
}
let main = MainClass()
main.showPopUp()
Or you could create a global variable so it can be accessed anywhere. ... It is better to pass data but I just thought it would be easier in this instance, so the variable can be accessed anywhere in your entire project.
if it is just a notification, you can show it in an alert, but if you don't want to use an alert my offer to present another view controller is not like this , try my code :
//if you have navigation controller ->
let vc = self.storyboard?.instantiateViewController(
withIdentifier: "storyboadrID") as! yourViewController
self.navigationController?.pushViewController(vc, animated: true)
//if you don't use navigation controller ->
let VC1 = self.storyboard!.instantiateViewController(withIdentifier: "storyboadrID") as! yourViewController
self.present(VC1, animated:true, completion: nil)
also if you want to pass any data or parameter to destination view controller you can put it like this before presenting your view controller :
VC1.textView.text = "test"

Could not cast value of type 'UITabBarController' to 'ViewController'

The situation: when I press a button in rentViewController, it pops up a tableviewcontroller. If a specific cell has been pressed, it sends data to rentViewController. In order to send data from one view controller to another I needed the code
let rentViewController : RentViewController = self.presentingViewController as! RentViewController <- here is where the error shows up
so that tableviewcontroller could get access to the variables and functions from rentviewcontroller. I'm using
self.dismiss(animated: true, completion: nil)
to get out of the tableviewcontroller and back to the rentviewcontroller. However, it gives me an error "Could not cast value of type 'UITabBarController' to 'RentViewController'". I did some research and I think it's according to the orders of my view controllers but I'm not sure how to change it in a way that it works. My initial view is 'TabBarController' and the order after that is 'NavigationController' -> 'RentViewController' -> 'TableViewController'. If you have questions feel free to ask I can provide you more information.
Your viewController is being presented from UITabBarController. With approach you are using I believe you can access it like this (where index is index in UITabBarController of your UINavigationController containing RentVC):
if let tab = self.presentingViewController as? UITabBarController,
let nav = tab.viewControllers?[index] as? UINavigationController,
let rentViewController = nav.viewControllers.first as? RentViewController {
rentViewController.data = data
}
However, I would suggest using a delegate or callback block to pass data in this occassion.
For delegate approach, first create protocol:
protocol PassDataDelegate:class {
func passData(data:YourType)
}
Then in TableViewController:
class TableViewController: UIViewController {
weak var delegate: PassDataDelegate?
}
And in RentViewController:
extension RentViewController: PassDataDelegate {
func passData(data:YourType) {
//use data to suit your needs
}
}
Before presenting TableViewController, in RentViewController, set its delegate:
tableViewController.delegate
present(tableViewController, animated: true)
And finally, inside TableViewController, before dismissing, call delegate's method to pass data:
delegate?.passData(data: <<someData>>)

Passing data between two view controllers are not working

I am trying to pass some data between two view controllers, but it doesn't work..
This is the data i am trying to pass(these has items from parse.com - the same code is in both view controllers):
var userFile = [PFFile]()
var createdAt = [NSDate]()
var objID = [String]()
This is the button for open the view controller(inside the first view controller i am trying to send data FROM):
#IBAction func openButtonAction(sender: AnyObject) {
let modalVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
modalVC.userFile = self.userFile
modalVC.createdAt = self.createdAt
modalVC.objID = self.objID
print("USERFILE: \(modalVC.userFile.count)")
presentViewController(modalVC, animated: true, completion: nil)
}
The view controller is a ModalViewController.xib connected to ViewStoryModalViewController.swift
This is the viewDidLoad in the view controller i am trying to send data TO:
override func viewDidLoad() {
super.viewDidLoad()
print("USERFILECOUNT: \(self.userFile.count)")
}
My problem is that this is the messages i get in xCode output:
What might be wrong here? Any suggestions?
xCode output tells that an array self.userFile contains zero elements, It doesn't mean that it is passed wrong. It is just empty.
print("USERFILECOUNT: \(self.userFile.count)")
Check if it is empty before passing it to modal vc.
Try this code
You first need to present after that try to set variable.
IBAction func openButtonAction(sender: AnyObject) {
let modalVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
print("USERFILE: \(modalVC.userFile.count)")
presentViewController(modalVC, animated: true, completion: nil)
modalVC.userFile = self.userFile
modalVC.createdAt = self.createdAt
modalVC.objID = self.objID
}

Swift after signup move to 2nd or any other tab of UITabBarController

In my App after signup/login I want to move control to specific tab of UITabBarController on some conditions. My login or Signup Pages are not in UITabBarController.
Here is the code of my login button I have tried but it only works with identifier or UITabBarController. In my case I want to move to specific tab like 2nd or 3rd tab.
#IBAction func btn_login(sender: AnyObject) {
activityIndicator.progressBarDisplayer("Logging In", true, uiView: self.view)
let timezone = GLib.timezone();
let parameters = ["email": txtemail.text!,"password": txtpassword.text!,"time_zone": timezone]
GLib.fetch("www.abc.com/test/auth/login", parameters: parameters, localkey: "user"){
(isResponse) -> Void in
if(isResponse == true)
{
self.activityIndicator.strLabel.text = "Personalizing Data";
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("some identifier") as UIViewController;
self.presentViewController(viewController, animated: false, completion: nil);
}else
{
self.show_alert("Attention Please!", message: self.GLib.error)
}
}
I have seen many posts but found nothing similar to my mechanism.
I am new to iOS programming so don't know how to figure out this issue.
Using instantiateViewControllerWithIdentifier is the right way to go. However, you need to add the actual identifier, and the UIViewController Custom class type needs to be the actual class.
I'm going to give you a rough example of what it looks like, but it should work. Either way you have to edit your instantiate method as I explain below.
Steps:
Firstly, set the "Storyboard ID" for the viewController in your storyboard. Like this:
Then add this code modified instantiateViewControllerWithIdentifier method:
#IBAction func btn_login(sender: AnyObject) {
activityIndicator.progressBarDisplayer("Logging In", true, uiView: self.view)
let timezone = GLib.timezone();
let parameters = ["email": txtemail.text!,"password": txtpassword.text!,"time_zone": timezone]
GLib.fetch("www.abc.com/test/auth/login", parameters: parameters, localkey: "user"){
(isResponse) -> Void in
if(isResponse == true)
{
self.activityIndicator.strLabel.text = "Personalizing Data";
let yourNewViewController: ViewControllerClassName = self.storyboard!.instantiateViewControllerWithIdentifier("yourStoryBoardID") as! ViewControllerYourePushingTo
self.presentViewController(yourNewViewController, animated: true, completion: nil)
}else
{
self.show_alert("Attention Please!", message: self.GLib.error)
}
}
As a type, you need to actually use the viewController's name.
I asked a similar question a few weeks ago: Swift: Triggering TableViewCell to lead to a link in a UIWebView in another ViewController

getting BAD_EXC_INSTRUCTION and Optional.None swift

I'm now very confused.
I am trying to set a label in one viewController by inputting text into a textbox on a secondView controller and pressing a button. When I do this however, I get a Optional.None error while trying to set the label - but the text is passed back as I can println it just fine from the 1st viewController...
I'm just using "HI" for testing purposes (saves time).
I obviously left out a lot of code here - if there is anything else you need please say.
First View Controller:
#IBAction func btnOptions(sender : AnyObject) {
var view: SecondViewController = SecondViewController()
self.presentViewController(view, animated: true, completion: nil)
}
func setLabel(text: String)
{
println(text)
lblTester.text = text
}
Second View Controller:
#IBAction func btnTester(sender : AnyObject) {
var first: ViewController = ViewController()
first.setLabel("HI")
self.dismissModalViewControllerAnimated(true)
}
lblTester is an outlet so before view is loaded it is nil (an optional value) or you are not initialised it, so you need to check for lblTester exist or not before setting value i.e
func setLabel(text: String)
{
println(text)
if let label = lblTester {
lblTester.text = text
}
}

Resources