Passing data between two view controllers are not working - ios

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
}

Related

Change order in Navigation Controller

I'm working with Swift3. I have an App with the VCs as in the picture.
In the Mainmenu-VC the user triggers the Input-segue. User enters a firstname in the Input-VC. This triggers the Select-segue to Select-VC to select a surname and trigger Selected-segue to Details-VC.
From the Mainmenu-VC the user can also access the Details-VC. Back via NavigationControllerMechanism to Mainmenu-VC.
I want to change the NavigationControllerMechanism 'history', so that when the user enters from the Details-VC via the Selected-segue, the previous VC is changed from Select-VC to Mainmenu-VC.
So basically when in the Details-VC, the Back always returns to Mainmenu-VC.
I have tried combining various solutions from the web, without succes.
Is this possible?
Yes it is.
The View-Controller stack is stored in currentViewController.navigationController?.viewControllers.
So you should make something like :
//In Your Details VC :
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard let stack = self.navigationController?.viewControllers else { return }
//get the mainMenu VC
let mainVC = stack.first!
// Rearrange your stack
self.navigationController?.viewControllers = [mainVC, self]
//Now you can press "bac" to Main VC
}
you want to change navigation stack in this way you can manipulate
let myprofile = storyboard.instantiateViewController(withIdentifier: "Profile1ViewController") as! Profile1ViewController
let sourseStack = self.navigationController!.viewControllers[0];
var controllerStack = self.navigationController?.viewControllers
let index = controllerStack!.index(of: sourseStack);
controllerStack![index!] = myprofile
self.navigationController!.setViewControllers(controllerStack!, animated: false);
to go to RootViewController
dispatch_async(dispatch_get_main_queue(), {
self.navigationController?.popToRootViewControllerAnimated(true)
})

How to pass information back with view controllers

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 :)

NSUserDefaults key becomes nil when sent between view controllers

I need to send a username between two view controllers so that the second view controller knows who to send a message to. I have tried prepareForSegue, however I have found that the variable passed cannot be dynamically altered. I decided to use NSUserDefaults, which worked very well for the length of my development process. Today, it stopped working. I do not think I deleted anything or made an changes, but nevertheless NSUserDefaults is no longer reliably carrying the value between the two view controllers. Every once in a while (maybe 20% of the time?) the value will be correctly passed. The rest of the time, nothing comes through.Code:
Set key:
func chooseFriend(sender: UIButton) {
let requestIndex = sender.tag
let friendChosen = self.friends.objectAtIndex(requestIndex) as! String
NSUserDefaults.standardUserDefaults().setValue("thisisatest", forKey: "testKey")
NSUserDefaults.standardUserDefaults().synchronize()
self.performSegueWithIdentifier("toChat", sender: self)
}
Note: In the viewDidLoad I set testKey = ""
Retrieve key on new view controller:
override func viewDidLoad() {
super.viewDidLoad()
let theKey = NSUserDefaults.standardUserDefaults().valueForKey("testKey")
print("The Key: \(theKey)")
refreshTable()
let swipe: UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "dismissKeyboard")
swipe.direction = UISwipeGestureRecognizerDirection.Down
self.view.addGestureRecognizer(swipe)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
testLabel.text = ""
self.messages.addObject("Loading......")
}
Every time, the default comes up empty: The Key: Optional()I can successfully print the default after setting it, however it disappears once I am segued to the next view controller...If anyone else has experienced this problem please let me know.Thanks
Randy's code:
func chooseFriend(sender: UIButton) {
let requestIndex = sender.tag
let friendChosen = self.friends.objectAtIndex(requestIndex) as! String
// Instantiate the second view controller via t's identifier in the storyboard
if let secondViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ChatVC") as? chatViewController {
// Set the chosen friend
secondViewController.friendChosen = friendChosen
self.presentViewController(secondViewController, animated: true, completion: nil)
}
}
Added this to destinationviewcontroller:
var friendChosen: String!
The methods for NSUserDefaults are setObject:forKey: and objectForKey:, not setValue:forKey: (Or look at the special methods for specific object types, like setBool:forKey: or stringForKey: (I don't think there's a custom set method for strings.))
The methods with "value" in their names are KVC methods.
But, as Randy says, using your app's model is a better way to go, or passing the information directly to a property in the destination view controller in prepareForSegue. Using NSUserDefaults would not be my first, or my second, choice in this situation.
It looks like you're using storyboards already so it should be pretty easy to pass information using prepareForSegue like this.
class DestinationVC : UIViewController {
var destName : String!
override func viewWillAppear(animated: Bool) {
//configure UI with the destName
self.label.text = destName
}
}
class PresentingVC : UIViewController {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destinationVC = segue.destinationViewController as? DestinationVC {
destinationVC.destName = "Some String to Pass"
}
}
}
As already mentioned NSUserDefaults is not ideal. You will also be loosing type safety and relying on string matching with keys in NSUserDefaults rather than autocompleting and compiler checking with a var on the destinationVC. It's also good practice to limit where your data is kept and where it could be altered. Storing something in NSUserDefaults when the use case is quite confined will make it more difficult to write focussed tests and make it vulnerable to change from any class anywhere in the app. It may be an edge case but starting a pattern like this in your app could expose you to all sorts of side effect bugs in the future.
Ultimately, this type of information should be passed from view controller to view controller in a model via a delegate. That would be the "appropriate" way to achieve this behavior via a true MVC pattern.
Having said that; I think the quickest fix for you would be not to use segues and to avoid NSUserDefaults all together.
Try the following...
func chooseFriend(sender: UIButton) {
let requestIndex = sender.tag
let friendChosen = self.friends.objectAtIndex(requestIndex) as! String
// Instantiate the second view controller via it's identifier in the storyboard
if let secondViewController = self.storyboard?.instantiateViewControllerWithIdentifier("SecondViewControllerIdentifier") as? SecondViewController {
// Set the chosen friend
secondViewController.friendChosen = friendChosen
self.presentViewController(secondViewController, animated: true, completion: nil)
}
}
And in the SecondViewController add the following property.
var friendChosen: String!
Please make sure the value is not nil prior to passing it to the destination view controller

Pass messages and/or objects between different storyboards swift

I've two storyboards and need to pass messages and objects. I know how to do it in the same storyboard and with .xib files, but not with two different storyboards.
My code is:
var storyboard = UIStoryboard(name: "RecibosStoryboard", bundle: nil)
var controller = storyboard.instantiateViewControllerWithIdentifier("RecibosStoryboard") as! UINavigationController
self.presentViewController(controller, animated: true, completion: nil).
// If i do: var controller = storyboard.instantiateViewControllerWithIdentifier("RecibosStoryboard") as! = TableRecibosViewController -> fails ->cannot convert TablaRecibosViewController to UINavigationController
// If i do:
/* var controller = storyboard.instantiateViewControllerWithIdentifier("RecibosStoryboard") as! UINavigationController
let vartest: TablaRecibosTableViewController = TablaTablaRecibosTableViewController()
prueba.inicioPrueba(str, strPrueba2: str2) -> two objects are nill
self.presentViewController(controller, animated: true, completion: nil).
Two objects are nill*/
My second storyboard is "RecibosStoryboard" and only has 1 view who class is TablaRecibosViewController and has a contructor method:
class TablaRecibosTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tablaRecibos: UITableView!
var pruebaMansajes: String?
var pruebaMansajes2: String?
var arrayOfObjectsCellRecibos: [ObjectTableRecibos] = [ObjectTableRecibos] ()
override func viewDidLoad() {
super.viewDidLoad()
tablaRecibos.dataSource = self
tablaRecibos.delegate = self
println("Pruebas satisfactorias1 \(pruebaMansajes) \(pruebaMansajes2)")
}
func inicioPrueba(strprueba1:String, strPrueba2:String){
pruebaMansajes = strprueba1
pruebaMansajes2 = strPrueba2
}
When i execute the App or crash or print two objects = nil
I don't find the way to do. Thanks a lot.
The problem is the following "cannot convert TablaRecibosViewController to UINavigationController". Your TablaRecibosViewController is embedded inside a UINavigationController. Try the following:
if let recibosViewController = (storyboard.instantiateViewControllerWithIdentifier("RecibosStoryboard") as? UINavigationController).viewControllers.first as? TablaRecibosTableViewController {
recibosViewController.pruebaMensajes = "Hola mundo"
}
You were creating a new instance of TablaTablaRecibosTableViewController() which was not associated to the Storyboard, therefore the table view was nil and it crashed.

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