I am trying to convert an app from Objective-C to Swift but I can't find how to pass data between views using Swift. My Objective-C code is
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
AnsViewController *ansViewController;
ansViewController = [storyBoard instantiateViewControllerWithIdentifier:#"ansView"];
ansViewController.num = theNum;
[self presentViewController:ansViewController animated:YES completion:nil];
What that is doing is it basically takes the variable, theNum, and passes it to the variable, num, on a different view controller. I know this may be an easy question but I am getting pretty confused with Swift so if someone could explain how they changed it to Swift that would be greatly appreciated!
Thanks
Let's assumed we stand at the firstView go to the DetailView and want passing data from firstView to Detailview. To do that with storyboard, at the firstView we will have a method:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "segueTest") {
//Checking identifier is crucial as there might be multiple
// segues attached to same view
var detailVC = segue!.destinationViewController as DetailViewController;
detailVC.toPass = textField.text
}
}
and then into the class of DetailView we declared a variable:
var toPass: String!
then you can use the variable toPass (of course you can change the type of the variable as you want, in this EX I just demo for string type).
class AnsViewController: UIViewController {
var theNum: Int
override func viewDidLoad() {
super.viewDidLoad()
println(theNum)
}
}
override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
let viewController = self.storyboard.instantiateViewControllerWithIdentifier("ansView") as AnsViewController
viewController.num = theNum
self.presentViewController(viewController, animated: true, completion: nil)
}
To pass string or any data from one controller to another in swift.
Follows below steps:
1) Create property in child controller as var abc:string!
2) Create object of childcontroller
let storyboard:UIStoryboard()
let viewController: childcontroller = storyboard.instantiateViewControllerWithIdentifier("childcontroller") as! childcontroller
viewController.abc = "hello";
self.navigationController.pushviewController(Controller:viewController animated:true CompletionHandler:nil)
Using tableview,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let ClubProfileView = self.storyboard?.instantiateViewController(withIdentifier: "CBClubProfileViewController") as! CBClubProfileViewController
let TempCulubDic:NSDictionary =
((ClubsListbyDateDic.object(forKey:((ClubsListbyDateDic.allKeys as! [String]).sorted(by: <)as NSArray).object(at: indexPath.section) as! String) as! NSArray).object(at: indexPath.row))as! NSDictionary
let ClubId:String=(TempCulubDic.value(forKey: "club_id") as? String)!
let CheckIndate:String=(TempCulubDic.value(forKey: "chekin_date") as? String)!
ClubProfileView.ClubID=ClubId
ClubProfileView.CheckInDate = CheckIndate
// self.tabBarController?.tabBar.isHidden=true
ClubProfileView.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(ClubProfileView, animated: true)
}
#IBAction func nextbtnpreesd(_ sender: Any) {
let mystring = "2"
performSegue(withIdentifier: "MusicVC", sender: mystring)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? MusicVC{
if let song = sender as? String{
destination.strlablevalie = song
}
}
}
//in MusicVC create string like:
var strlablevalie:String!
To pass string or any data from one controller to another in swift.
Follows below steps:
1) Create variable of type which you want like (String,Int)
var test : String!
2) Create object of childcontroller
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Here identifier of your VC") as! (Here Name Of Your Controller)
vc.test = "Hello" (Or any data which you want to pass)
self.navigationController?.pushViewController(VC, animated: true)
That should solve your problem
Note: if we are using storyboard
Step 1: Master controller :
// table row which row was selected
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
println("You selected cell #\(indexPath.row)!")
nextScreenRow = indexPath.row
// get to the next screen
self.performSegueWithIdentifier("dashboard_static_screen_segue", sender: self)
}
and then;
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "dashboard_static_screen_segue") {
var detailController = segue.destinationViewController as StaticScreens;
detailController.screenNumber = nextScreenRow
}
}// end prepareForSegue
step 2: Detail controller (StaticScreen)
// set variable into your detail controller
var screenNumber: NSInteger?
println("selected row \(screenNumber!)")
Related
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 3 years ago.
My scenario, I am trying to get JSON data using codable format. I need to pass the decoder value to another view controller after click the Tableview custom cell. I don't know how to do that, I seen some example but its not clear.
My Code below
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//print("You tapped cell number \(indexPath.row).")
let section = isFiltering ? filteredSections[indexPath.section] : sections[indexPath.section]
let item = section.result[indexPath.row]
print("\(item)")
let vc = self.storyboard?.instantiateViewController(withIdentifier: "secondviewcontroller") as! SecondViewController
vc.dataset = item
let navigationController = UINavigationController(rootViewController: vc)
self.present(navigationController, animated: true, completion: nil)
}
This is a segue from a cell to a ViewController that performs on cell selection, for this you want to do:
var selectedItem: Item?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondViewController = (segue.destination as? UINavigationController)?.topViewController as? SecondViewController {
if let item = selectedItem {
secondViewController.dataset = selectedItem
}
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// Here you are only setting the item variable to the selected one so you can grab it in the prepare func
// No need to call the segue because the storyboard linkage from cell to controller will be used to call the segue
let section = isFiltering ? filteredSections[indexPath.section] : sections[indexPath.section]
selectedItem = section.result[indexPath.row]
}
This is a segue from a ViewController to a ViewController, for this you want to:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let secondViewController = (segue.destination as? UINavigationController)?.topViewController as? SecondViewController {
if let item = sender as? Item {
secondViewController.dataset = selectedItem
}
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// Here the controller will not automatically perform the segue on selection
// You call the performSegue function and send the selected item as sender
// The item will be available in the prepare function
let section = isFiltering ? filteredSections[indexPath.section] : sections[indexPath.section]
performSegue(withIdentifier: "secondviewcontroller", sender: section.result[indexPath.row])
}
I have two VC, the first is a tableView, the second is the detailedView VC where you can add a new item to the tableView.
I have implemented passing data forward with segues (from plus button in the first VC) and backwards with delegate and protocol when adding a new item to the tableView (triggered when tapping a save button on the second VC).
I added a segue from the prototype cell to the second VC (detailed view), I have also managed to test in the first VC which segue is triggered, ie: add new item or go to the detailedView of that item. the problem I'm facing, the save button in the second VC no longer works (and the cancel button also), I want to be able to edit the text fields in the second VC and hit the save button to save the edited item back in the first one.
I found a way to implement it with unwind segues, however I would like to know how to do it with delegate ?
My first VC code:
class ThingsTableViewController: UITableViewController, CanReceive {
var myThings = [Thing]()
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myThings.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = myThings[indexPath.row].name
cell.detailTextLabel?.text = myThings[indexPath.row].type
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "addNewThing" {
let secondVC = segue.destination as! UINavigationController
let ThingsViewController = secondVC.topViewController as! ThingsViewController
ThingsViewController.delegate = self
} else if segue.identifier == "showDetail" {
guard let thingDetailViewController = segue.destination as? ThingsViewController else {fatalError("Unknown Destination")}
guard let selectedCell = sender as? UITableViewCell else {
fatalError("Unexpected sender: \(sender)")
}
guard let indexPath = tableView.indexPath(for: selectedCell) else {
fatalError("The selected cell is not being displayed by the table")
}
let selectedThing = myThings[indexPath.row]
thingDetailViewController.thing = selectedThing
}
}
func dataReceived(data: Thing) {
if let selectedIndexPath = tableView.indexPathForSelectedRow {
myThings[selectedIndexPath.row] = data
tableView.reloadRows(at: [selectedIndexPath], with: .none)
} else {
myThings.append(data)
tableView.reloadData()
}
}
the code in the second vc look like:
protocol CanReceive {
func dataReceived(data: Thing)
}
}
class ThingsViewController: UIViewController, UITextFieldDelegate {
var delegate : CanReceive?
var thing : Thing?
#IBOutlet weak var thingNameTextField: UITextField!
#IBOutlet weak var thingTypeTextfield: UITextField!
#IBAction func saveThingButton(_ sender: UIBarButtonItem) {
let newThing = Thing(name: thingNameTextField.text!, type: thingTypeTextfield.text!)
delegate?.dataReceived(data: newThing)
self.dismiss(animated: true, completion: nil)
self.navigationController?.popViewController(animated: true)
}
#IBAction func cancelButton(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: nil)
self.navigationController?.popViewController(animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
thingNameTextField.delegate = self
updateSaveButtonState()
if let thing = thing {
navigationItem.title = thing.name
thingNameTextField.text = thing.name
thingTypeTextfield.text = thing.type
}
}
// MARK: UITextField Delegate
// get triggered when the user hit the return key on the keyboard
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
thingNameTextField.resignFirstResponder()
self.navigationItem.rightBarButtonItem?.isEnabled = true
return true
}
//gives chance to read info in text field and do something with it
func textFieldDidEndEditing(_ textField: UITextField) {
updateSaveButtonState()
navigationItem.title = thingNameTextField.text
}
func updateSaveButtonState() {
let text = thingNameTextField.text
self.navigationItem.rightBarButtonItem?.isEnabled = !text!.isEmpty
}
}
You're setting delegate for case that segue's identifier is addNewThing, but what about case that identifier is showDetail?
Set delegate of segue's destination for case that segue's identifier is showDetail
if segue.identifier == "addNewThing" {
...
} else if segue.identifier == "showDetail" {
...
thingDetailViewController.delegate = self
...
}
Then when you need to dismiss ViewController embed in navigation controller, just dismiss it and then dismiss navigation controller
In ThingsViewController class, please define delegate with weak var
weak var delegate: CanReceive?
One more issue is observed,
Looks like your instance name and class name are same, please update the instance name,
if segue.identifier == "addNewThing" {
let secondVC = segue.destination as! UINavigationController
let thingsVC = secondVC.topViewController as! ThingsViewController
thingsVC.delegate = self
} else if segue.identifier == "showDetail" {
guard let thingDetailViewController = segue.destination as?
ThingsViewController else {fatalError("Unknown Destination")}
guard let selectedCell = sender as? UITableViewCell else {
fatalError("Unexpected sender: \(sender)")
}
guard let indexPath = tableView.indexPath(for: selectedCell) else {
fatalError("The selected cell is not being displayed by the table")
}
let selectedThing = myThings[indexPath.row]
thingDetailViewController.thing = selectedThing
thingDetailViewController.delegate = self
}
Your tableView.reloadData() should happen in main queue
func dataReceived(data: Thing) {
myThings.append(data)
DispatchQueue.main.async {
tableView.reloadData()
}
}
Declare a protocol for receiving data.
protocol ViewControllerDelegate: class {
func didTapButton(with data: Int)
}
declare a delegate of protocol where you are sending the data
class SecondVC: UIViewController {
weak var delegate: ViewControllerDelegate?
#IBAction func buttonPressed(_ sender: UIButton) {
delegate?.didTapButton(with: sender.tag)
}
}
confirm to the protocol where you want to receive the data and make the delegate to self.
class FirstVC : UIViewController,ViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
func gotoSecond() {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "identifier") as! SecondVC
vc.delegate = self
self.navigationController?.pushViewController(vc, animated: true)
}
func didTapButton(with data: Int) {
print(data)
}
}
I've put a navigation controller in between viewcontrollers according to my project. When I tried to pass the data its shows the following error:
Could not cast value of type 'UINavigationController' (0x10900b008) to 'uday.Food_Drinks_DetailTableViewController' (0x105b72600).
This is my code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "fdShow", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "fdShow"{
if let indexpath = tablevi.indexPathForSelectedRow {
let fddVc = segue.destination as! Food_Drinks_DetailTableViewController
fddVc.FdString = fad[indexpath.row]
}
}
}
I'm getting the error at the following line:
let fddVc = segue.destination as! Food_Drinks_DetailTableViewController
I think your segue destination is UINavigationController.If you are not using custom class for navigation controller. You need to change code to
let navVc = segue.destination as! UINavigationController
and then, if Food_Drinks_DetailTableViewController is the first controller in navigation controller
let fddVc = navVc.viewControllers.first as! Food_Drinks_DetailTableViewController
fddVc.FdString = fad[indexpath.row]
I am trying to pass value from Realm via segue to another viewcontroller. The problem is it is crashing with error : Reciever has no segue with identifier. I tried other way, prepareforsegue but it is not working as well as this one.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let lektire = datasource[indexPath.row]
let destinationVC = DetaljiViewController()
destinationVC.programVar = lektire.ime
destinationVC.performSegueWithIdentifier("oLektiri", sender: self)
}
However, my segue is definitely there, and its identifier is properly set (see screen shot below).
What is going on, and how can I fix this problem?
I believe this is what you are looking for you have to call performSegueWithIdentifier from the view controller you are currently inside of and either make the sender the indexPath or you can make it your datasource item.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("oLektiri", sender: indexPath)
// Another WAY
self.performSegueWithIdentifier("oLektiri", sender: datasource[indexPath.row])
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "oLektiri") {
let indexPath = sender as! NSIndexPath
let toViewController = segue.destinationViewController as? NextViewController
let lektire = datasource[indexPath.row]
toViewController?.selectedObject = lektire
}
// Another WAY
if(segue.identifier == "oLektiri") {
let lektire = sender as? lektireTYPE
let toViewController = segue.destinationViewController as? NextViewController
toViewController?.selectedObject = lektire
}
}
// An example of what the next view controller should look like
class NextViewController: UIViewController {
var selectedObject: ObjectType?
}
I am trying to convert an app from Objective-C to Swift but I can't find how to pass data between views using Swift. My Objective-C code is
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
AnsViewController *ansViewController;
ansViewController = [storyBoard instantiateViewControllerWithIdentifier:#"ansView"];
ansViewController.num = theNum;
[self presentViewController:ansViewController animated:YES completion:nil];
What that is doing is it basically takes the variable, theNum, and passes it to the variable, num, on a different view controller. I know this may be an easy question but I am getting pretty confused with Swift so if someone could explain how they changed it to Swift that would be greatly appreciated!
Thanks
Let's assumed we stand at the firstView go to the DetailView and want passing data from firstView to Detailview. To do that with storyboard, at the firstView we will have a method:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "segueTest") {
//Checking identifier is crucial as there might be multiple
// segues attached to same view
var detailVC = segue!.destinationViewController as DetailViewController;
detailVC.toPass = textField.text
}
}
and then into the class of DetailView we declared a variable:
var toPass: String!
then you can use the variable toPass (of course you can change the type of the variable as you want, in this EX I just demo for string type).
class AnsViewController: UIViewController {
var theNum: Int
override func viewDidLoad() {
super.viewDidLoad()
println(theNum)
}
}
override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
let viewController = self.storyboard.instantiateViewControllerWithIdentifier("ansView") as AnsViewController
viewController.num = theNum
self.presentViewController(viewController, animated: true, completion: nil)
}
To pass string or any data from one controller to another in swift.
Follows below steps:
1) Create property in child controller as var abc:string!
2) Create object of childcontroller
let storyboard:UIStoryboard()
let viewController: childcontroller = storyboard.instantiateViewControllerWithIdentifier("childcontroller") as! childcontroller
viewController.abc = "hello";
self.navigationController.pushviewController(Controller:viewController animated:true CompletionHandler:nil)
Using tableview,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let ClubProfileView = self.storyboard?.instantiateViewController(withIdentifier: "CBClubProfileViewController") as! CBClubProfileViewController
let TempCulubDic:NSDictionary =
((ClubsListbyDateDic.object(forKey:((ClubsListbyDateDic.allKeys as! [String]).sorted(by: <)as NSArray).object(at: indexPath.section) as! String) as! NSArray).object(at: indexPath.row))as! NSDictionary
let ClubId:String=(TempCulubDic.value(forKey: "club_id") as? String)!
let CheckIndate:String=(TempCulubDic.value(forKey: "chekin_date") as? String)!
ClubProfileView.ClubID=ClubId
ClubProfileView.CheckInDate = CheckIndate
// self.tabBarController?.tabBar.isHidden=true
ClubProfileView.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(ClubProfileView, animated: true)
}
#IBAction func nextbtnpreesd(_ sender: Any) {
let mystring = "2"
performSegue(withIdentifier: "MusicVC", sender: mystring)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? MusicVC{
if let song = sender as? String{
destination.strlablevalie = song
}
}
}
//in MusicVC create string like:
var strlablevalie:String!
To pass string or any data from one controller to another in swift.
Follows below steps:
1) Create variable of type which you want like (String,Int)
var test : String!
2) Create object of childcontroller
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Here identifier of your VC") as! (Here Name Of Your Controller)
vc.test = "Hello" (Or any data which you want to pass)
self.navigationController?.pushViewController(VC, animated: true)
That should solve your problem
Note: if we are using storyboard
Step 1: Master controller :
// table row which row was selected
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
println("You selected cell #\(indexPath.row)!")
nextScreenRow = indexPath.row
// get to the next screen
self.performSegueWithIdentifier("dashboard_static_screen_segue", sender: self)
}
and then;
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "dashboard_static_screen_segue") {
var detailController = segue.destinationViewController as StaticScreens;
detailController.screenNumber = nextScreenRow
}
}// end prepareForSegue
step 2: Detail controller (StaticScreen)
// set variable into your detail controller
var screenNumber: NSInteger?
println("selected row \(screenNumber!)")