I'm learning Swift and I am working through passing items from one segue to another. From what it seems to me in the code, you are creating a new ViewController object called "secondVC". In line 3, it seems to me like it's duplicating the segue.destinationViewController by setting this new controller equal to the segue.destinationViewController. In other words, I don't understand how secondVC is actually a reference to this second view controller, instead of being a duplicated instance. Where is my fault in thinking? Here is the code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var secondVC:SecondViewController = SecondViewController()
secondVC = segue.destinationViewController as SecondViewController
secondVC.delegate = self
}
Thank you very much!
I'm learning swift too - From my own experience, you use prepareForSegue to pass in data to the secondVC right before the segue starts.
Here's some sample code. I use prepareForSegue to pass in task data into the second view controller. There are other ways to do this, this is just one way.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showTaskDetail" {
let detailVC: TaskDetailViewController = segue.destinationViewController as TaskDetailViewController
let indexPath = self.tableView.indexPathForSelectedRow()
let thisTask = fetchedResultsController.objectAtIndexPath(indexPath!) as TaskModel
detailVC.detailTaskModel = thisTask
detailVC.delegate = self
}
Related
I have VC "A", from which I pass some data to "B". In attribute inspector i called my seque "B" :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "B" {
let vc = segue.destination as! ChooseController
vc.someData = "passedDataFromAToB"
}
After that i want to pass some data back from B to A using delegates and protocols, but it turns out that my segue identifier is busy. I have to create new segue? But how, programmatically?
You need to set the delegate here
let vc = segue.destination as! ChooseController
vc.delegate = self
vc.someData = "passedDataFromAToB"
class ChooseController:UIViewController {
weak var delegate:AVC?
then to pass data before dismiss
delegate?.sendData(data)
self.dismiss(animated:true,completion:nil)
I have a variable called correctAnswers = 0 at the top of my program, I have a function where every time it is called it adds 1 to the correctAnswers value. I tested that the function was actually changing the variable by making it print after every +1 and sure enough it goes 1, 2, 3, 4 and so on. However I have an end screen that shows the results after the program has reached its limit of questions (10 in this case)
EDIT #2: Here is my prepare for segue function
func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "EndScreenSegue") {
let secondViewController = segue.destination as! EndScreen
correctAnswers = sender as! Int
secondViewController.gso = self
}
}
And here is the code in my end screen:
var gso: GameScreen?
override func viewDidLoad() {
super.viewDidLoad()
gso = GameScreen()
print(gso?.correctAnswers ?? 100)
}
When I print correct Answers it is still 0.
EDIT #3 I also tried this method of passing it through a segue and it is always nil. Does the fact its not working have anything to do with the fact the variable is being changed in a function? thats the only reason I can possibly think of to explain why nothing is working.
func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "EndScreenSegue") {
let secondViewController = segue.destination as! EndScreen
secondViewController.recievedAnswers = correctAnswers
}
}
class EndScreen: UIViewController{
var recievedAnswers: Int!
override func viewDidLoad() {
super.viewDidLoad()
print(recievedAnswers!)
}
}
EDIT #4 Figured it out! I think.
It appears they changed prepareForSegue and it no longer works, yet xcode does not give you an error? Should another post be made about this??
Code that actually works:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EndScreenSegue"{
let secondViewController = segue.destination as! EndScreen
secondViewController.recievedAnswers = correctAnswers
}
}
You're creating a new instance of GameScreen in the viewDidLoad method of your EndScreen view controller. You need to pass the GameScreen object from your previous view controller to this one.
In your segue you're setting the correctAnswers property of your EndScreen view controller, but you're printing the value of gso?.correctAnswers. A new gso was just instantiated prior to this print statement and (I'm assuming) has a default value of 0 which is why you're getting 0 printed out.
You either need to pass the GameScreen through the segue (assuming that you're segueing from GameScreen), like so:
func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "EndScreenSegue") {
let secondViewController = segue.destination as! EndScreen
correctAnswers = sender as! Int
secondViewController.gso = self
}
}
Or you can just pass the correctAnswers through the segue as you're doing but be sure to use that value, not gso?.correctAnswers
class EndScreen: UIViewController{
var correctAnswers: Int?
override func viewDidLoad() {
super.viewDidLoad()
print(correctAnswers ?? 100)
}
}
You are creating a new instance of GameScreen.
Delete this line gso = GameScreen() from viewDidLoad
For some reason it looks like prepareForSegue no longer works, yet xcode does not give an error when you use it. The correct format now is:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EndScreenSegue"{
let secondViewController = segue.destination as! EndScreen
secondViewController.recievedAnswers = correctAnswers
}
}
I have been following a firebase tutorial to create my own chat application, I am trying to access a chatviewcontroller from the uiviewcontroller containing a table view. The Viewcontroller is embedded in a navigation controller. How can I bring up the chatviewcontroller when a cell is selected?
Here is my code:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
//retrieve the destination view controller
let navVc = segue.destination as! UINavigationController
let channelVc = navVc.viewControllers.chatViewController as! ViewController
// set the senderDisplayName in Viewcontroller to the email provided in the email field by the user
channelVc.senderDisplayName = userEmailTextField?.text
}
Here is the error msg
Assuming your ChatViewController is the root view controller of your navigation controller you should change your code to this:
let channelVc = navVc.viewControllers.first as! ChatViewController
navVC.viewControllers is an array of the UIViewControllers managed by that UINavigationController, so that array would not have a property called chatViewController unless you implemented something custom.
EDIT: To put it all together, and also to demonstrate how to safely unwrap these optionals, your prepareForSegue should look like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
if let navVc = segue.destination as? UINavigationController, let channelVc = navVc.viewControllers.first as? ChatViewController {
//Now you have a reference to your ChatVC, and you can set the DisplayName
channelVc.senderDisplayName = userEmailTextField?.text
}
}
You have to get the first view controller from the UINavigationController:
let channelVc = navVc.viewControllers.first as! ChatViewController
I have two view controllers (fitstViewController.swift and secondViewController.swift) in navigation controler.
My idea is that
In firstViewController there are a button and a textFIeld. When I click the button, value in the textField is passed to secondViewController.
However it makes an error "Thread 1: signal SIGABRT" in the first controller.
Here is the code in the first controller..
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destination = segue.destinationViewController as! UINavigationController
let detailController = destination.topViewController as! secondViewController
detailController.stockSymbol = textField.text
}
I added just one line in the second controller..
var stockSymbol:String!
How can it be solved?
Thank you in advance!
In second controller the declared variable should be
var stockSymbol:String?
You should not force unwrap it unless you are sure that it would never be nil.
Replace your old code by:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard let destination = segue.destinationViewController as? SecondViewController else { return }
destination.stockSymbol = textField.text
}
I am developing an iOS application in Swift.
I want to send data from a view to an other one, using the prepareForSegue function.
However, my target view is preceded by a navigation controller, so it doesn't work. How can I set data on the VC contained within the navigation controller?
In prepareForSegue access the target navigation controller, and then its top:
let destinationNavigationController = segue.destination as! UINavigationController
let targetController = destinationNavigationController.topViewController
From the target controller you can access its view and pass data.
In old - now obsolete - versions of Swift and UIKit the code was slightly different:
let destinationNavigationController = segue.destinationViewController as UINavigationController
let targetController = destinationNavigationController.topViewController
Prepare the segue in the SendViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segueShowNavigation" {
if let destVC = segue.destination as? UINavigationController,
let targetController = destVC.topViewController as? ReceiveViewController {
targetController.data = "hello from ReceiveVC !"
}
}
}
Edit the identifier segue to "showNavigationController"
In your ReceiveViewController add
this
var data : String = ""
override func viewDidLoad() {
super.viewDidLoad()
print("data from ReceiveViewController is \(data)")
}
Of course you can send any other type of data (int, Bool, JSON ...)
Complete answer using optional binding and Swift 3 & 4:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let navigationVC = segue.destination as? UINavigationController, let myViewController = navigationVC.topViewController as? MyViewControllerClass {
myViewController.yourProperty = myProperty
}
}
Here is the answer for Swift 3:
let svc = segue.destination as? UINavigationController
let controller: MyController = svc?.topViewController as! MyController
controller.myProperty = "Hi there"
A one liner in Swift 3:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination.childViewControllers[0] as? FooController {
vc.variable = localvariable
}
}
In Swift 5
If you must not only segue from a SourceViewController to a DestinationViewController embedded in a UINavigationController, but also to a new Storyboard also, then do the following...
Place a "Storyboard Reference" object from your Object Library next to your source ViewController in Interface Builder, and then drag a segue to it (from a button on the SourceViewController view, for instance). Name the segue identifier "ToOtherStoryboard", for example.
Go to NavigationViewController and give it a Storyboard ID using the Identity Inspector. "DestinationNavVC" would do.
Click the Storyboard Reference icon you created in step 1, and in its attribute inspector's 'Referenced ID' field, enter the Storyboard ID you wrote for the UINavigationController in step 2. This creates the segue from source to the DestinationViewController no matter what you write in source file of the source ViewController. This is because seguing to a NaviationController will automatically show the root ViewController (the first one) of the UINavigationController.
(OPTIONAL) If you need to attach data along with your segue and send it to properties within the DestinationViewController, you would write the following code inside a Prepare-For-Segue method in your SourceViewController file:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ToOtherStoryboard" {
let destinationNavVC = segue.destination as! UINavigationController
let destinationVC = destinationNavVC.topController as! DestinationViewController
destinationVC.name = nameTextField.text // for example
destinationVC.occupation = occupationTextField.text
}
}
You do not NEED to have a PrepareForSegue if you're simply trying to move from one ViewController to another, the methods above will work (w/o step 3)
In your IBAction Outlet method for your button you used to initiate the segue, you would write:
performSegue(withIdentifer: "ToOtherStoryboard", sender: self)
Set the identifier name in the segue arrow property in order to use in the the performeSegue.
Like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc: ProfileViewController = segue.destination as? ProfileViewController {
//do any setting to the next screen
}
}
and then:
performSegue(withIdentifier: "yourIdentifierOfViewProfile", sender: indexPath.row)
I hope it helps.
It's a good idea to skip the check for UINavigationController as there may be multiple segues that use a navigationController and so will go into that check for every segue that uses a navigationController. A better way is to check the first viewController of the children and cast it as the viewController you are looking for.
if let destVC = segue.destination.children.first as? MyViewController {
destVC.hideBottomBar = true
}