Pass a variable between controllers - Swift4 - ios

I'm trying to pass 1 variable to another view controller and then another view controller.
var selectedPlace = Place {
name = Daniel Webster Highway;
country = United States;
lat = 42.72073329999999;
lon = -71.44301460000001;
}
When I select on a cell, I have access to a variable selectedPlace
I want to pass it on to my PlaceDetailVC and also MapVC.
For some reasons, I can't make that happen.
PlacesVC
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as! PlaceDetailVC
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.selectedPlace = (places?[indexPath.row])!
destinationVC.selectedTrip = selectedTrip!
}
}
PlaceDetailVC
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toMap" {
let destinationVC = segue.destination as! MapVC
if let indexPath = placesTable.indexPathForSelectedRow {
destinationVC.selectedPlace = selectedPlace
}
}
}
I also try
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as! MapVC
if let indexPath = placesTable.indexPathForSelectedRow {
destinationVC.selectedPlace = selectedPlace
}
}
MapVC
print(selectedPlace,"<<<<<<")
Result
I kept getting
Any hints on what I did wrong ?

No need to check indexPath if the segue "toMap" is called by the nav button
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toMap" {
let destinationVC = segue.destination as! MapVC
destinationVC.selectedPlace = selectedPlace
/*
if let indexPath = placesTable.indexPathForSelectedRow {
destinationVC.selectedPlace = selectedPlace
}*/
}
}

Related

VC presenter is not being initialized prepare for segue IOS swift

Hello i am facing the problem as the prepare for segue function is not working properly i've the code can you please tell me how can i debug it as it has optional conditions how i can remove them and check what's the problem or what i am doing wrong as i just want a class to be initialized in target vc before the app navigates to other screen.
#IBAction func filterBtnPressed(_ sender: Any) {
self.performSegue(withIdentifier: "FilterSessionVC", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "FilterSessionVC", let navigation = segue.destination as? UINavigationController, let vc = navigation.topViewController as? FilterSessionVC {
vc.presenter = FilterSessionPresenterImplementation()
}
}
Basic debugging...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let identifier = segue.identifier
print("identifier:", identifier)
let dest = segue.destination
print("destination:", dest)
if let navigation = dest as? UINavigationController {
print("dest IS a UINavigationController")
if let vc = navigation.topViewController as? FilterSessionVC {
print("Top Controller IS a FilterSessionVC")
// here you can proceed
vc.presenter = FilterSessionPresenterImplementation()
} else {
print("Top Controller IS NOT a FilterSessionVC")
}
} else {
print("dest IS NOT a UINavigationController")
}
}
Set a breakpoint on the first line, then step through and inspect the results.

How to create sender.tag UIButton in another function?

I have an array of answers and an array of buttons. When I click on a particular button, with the help of a sender.tag, I have an index change. I also need to do in override func prepare(for segue: UIStoryboardSegue, sender: Any?) so that the answer is set by the index and the result will go to another screen.
When i tried to create sender.tag i have error
Value of type 'Any?' has no member 'tag'
#IBAction func answerPressed(_ sender: UIButton) {
let index = sender.tag
let currentAnswer = currentQuestions?.answers[index]
if currentAnswer!.type != .next {
performSegue(withIdentifier: "segue", sender: sender)
} else {
currentQuestions = currentAnswer!.nextQuestion
updateTittles(currentQuestions)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let index = sender.tag
let currentType = currentQuestions?.answers[index].type
let resultViewController = segue.destination as! ResultViewController
resultViewController.type = currentType
}
The sender in this case for the prepare for segue function is not necessarily a UIButton, it's whatever initiated the segue. You could check to see if it's a button by trying to cast it to one as follows:
if let button = sender as? UIButton {
index = button.tag
}
What you could also do is in the answerPressed function instead of performing a segue you could instantiate the ResultViewController yourself there and then push to it. Because when you're in this function you know that the sender is a UIButton and it should have a tag.
As Anything can be the type of sender the parameter is declared as Any
First check for the identifier of the segue, on success force downcast the sender parameter to UIButton
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "segue" else { return }
let button = sender as! UIButton
let currentType = currentQuestions?.answers[button.tag].type
let resultViewController = segue.destination as! ResultViewController
resultViewController.type = currentType
}
But it's not necessary to pass the entire UIButton instance, the tag/index is sufficient, or – even more efficient – pass currentAnswer.type
#IBAction func answerPressed(_ sender: UIButton) {
let index = sender.tag
let currentAnswer = currentQuestions?.answers[index]
if currentAnswer!.type != .next {
performSegue(withIdentifier: "segue", sender: index)
} else {
currentQuestions = currentAnswer!.nextQuestion
updateTittles(currentQuestions)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "segue" else { return }
let index = sender as! Int
let currentType = currentQuestions?.answers[index].type
let resultViewController = segue.destination as! ResultViewController
resultViewController.type = currentType
}
Value of type 'Any?' has no member 'tag'
Means that Any object has no indeed a tag property. You know your sender is a UIButton, so why not CAST that sender of prepareForSegue to a UIButton object, like so?
guard let buttonSender = sender as? UIButton else { return }

IOS/Swift: Pass Object in tableview to detail view controller

I am trying to grab an object from a tableview and pass it to a detail view, something I know how to do in Objective-C but am learning for first time Swift. However, my code is not getting the row from the index path or object.
Here is my code.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("segue")
if segue.identifier == "showDetail"{
if let destinationVC = segue.destination as? detailVC {
)
if let indexPath = self.tableView.indexPathForSelectedRow {
print("row%#",indexPath)//Prints as nil
let thisItem = myItems[indexPath.row]//never gets here
destinationVC.item = thisItem
}
}
}
}
Can anyone see why I am not getting the row or the object? Thanks in advance for any suggestions.
Edit:
I got it to work with following:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
let indexPath: NSIndexPath = self.tableView.indexPathForSelectedRow! as NSIndexPath
let anItem: myItem = myItems[indexPath.row];
let destVC = segue.destination as? detailVC
destVC?.item = anItem
}
}
Implement UITableViewDelegate method,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = myItems[indexPath.row]
self.performSegue(withIdentifier: "showDetail", sender: item)
}
then implement below,
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showdetail" {
let detailController = segue.destination as! detailVC
detailController.item = sender as! Your_Item
}
}
Why don't you use these methods to save the value of the selected row or item? and then perform segue?
tableView(_:didDeselectRowAt:)
tableView(_:didSelectRowAt:)

How to pass data from textfield to another textfiled?

override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
var secondController = segue.destination as! EditBillsViewController
secondController.textField = items
secondController.notesTextBox = notes
secondController.billNameTextBox = billsName
secondController.dateToPayTextBox = DatePickerText
secondController.DailyReminerTextBox = DaysNotification
First you get the Text from your textfield and then set it to the text of your second textfield.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let text = self.firstTextField.text else {
print("something Went wrong")
return
}
var secondController = segue.destination as! EditBillsViewController
secondController.textFieldValue = text
secondController.notesTextBox = notes
secondController.billNameTextBox = billsName
secondController.dateToPayTextBox = DatePickerText
secondController.DailyReminerTextBox = DaysNotification
}

Passing object with prepareForSegue Swift

I am trying to pass an object to another scene with prepareForSegue()
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
var nextScene = segue.destinationViewController as! VehicleDetailsTableViewController
// Pass the selected object to the new view controller.
if let indexPath = self.tableView.indexPathForSelectedRow() {
let selectedVehicle = vehicles[indexPath.row]
nextScene.currentVehicle = selectedVehicle
}
}
And I have currentVehicle object to catch these object. But, when I try to run, it brokes and get error about downcasting.
Error EDIT
Could not cast value of type 'XXX.DisplayViewController'
(0x1082dcd80) to 'XXX.VehicleDetailsTableViewController'
(0x1082dc9a0). (lldb)
You have to give the segue an identifier in the storyboard.(say mySegue)
Using Xcode 10 swift 4.x(Also works with Xcode 9 & 8 , swift 3.x)
override func prepare(for segue: UIStoryboardSegue, sender: Any?){}
Is called for all segues being called from your current UIViewController. So the identifier is to differentiate the different segues
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mySegue" ,
let nextScene = segue.destination as? VehicleDetailsTableViewController ,
let indexPath = self.tableView.indexPathForSelectedRow {
let selectedVehicle = vehicles[indexPath.row]
nextScene.currentVehicle = selectedVehicle
}
}
If you are using Using Xcode 7, swift 2.x
Then use this code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "mySegue" {
var nextScene = segue.destinationViewController as! VehicleDetailsTableViewController
// Pass the selected object to the new view controller.
if let indexPath = self.tableView.indexPathForSelectedRow {
let selectedVehicle = vehicles[indexPath.row]
nextScene.currentVehicle = selectedVehicle
}
}
}
Place a breakpoint after nextScene and see if it is being triggered by clicking any cell in the TableView. If it isn't then the identifier name u provided in the storyboard must be different then the one given here.
In swift 3.0 Xcode 8 beta 6
AnyObject has been renamed to Any?
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
let nextScene = segue.destinationViewController as! VehicleDetailsTableViewController
// Pass the selected object to the new view controller.
if let indexPath = self.tableView.indexPathForSelectedRow {
let selectedVehicle = vehicles[indexPath.row]
nextScene.currentVehicle = selectedVehicle
}
}
}
In Swift 3, Xcode 8
Just don't use "identifier". I don't know why but "segue.identifier" is always nil. I just used prepare method like this and works!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondController = segue.destination as? SecondController {
secondController.anyItemInSecondController = self.anyItemInFirstController
}
What that error is telling you is that segue.destinationViewController isn't a VehicleDetailsTableViewController. We don't have enough details to tell you why.
Check your segues and make sure they're all pointing to the correct place, and always check the identifier of your segue before you perform a cast.
if segue.identifier == "theNameOfYourSegue" // then do your cast

Resources