Edit: mentioned at the bottom I was using another stackoverflow question for guidance. Turns out its the same issue that I don't believe ever got solved after the person edited their question. So I copied the exact same issue into my code: How to know which cell was tapped in tableView using Swift
There's probably many things wrong with my code at this point, but the main issue is the very edit at the bottom of the post this author puts on his question. I know that makes this a duplicate then but no one has answered that. All the accepted answers have the same outcome as my issue.
I'm very new to swift and I'm creating a flashcard type app where tapping on a tableview cell for details shows a term and definition. These terms and definitions are stored in two parallel arrays and the index is supposed to be the indexPath.row.
My issue is that int selectedCell which should be the index of the array for whichever cell the user taps always runs the code to display the term and definition before running the code to find the selected cell.
My earlier error before this was that if I made selected cell an optional (var selectedCell: Int?), the program would crash because its nil. To fix that, I made it var selectedCell: Int = 0 and that worked until I realized that no matter what I tap, the first selectedCell will always be 0.
How can I get the selectedCell before the terms and definitions are displayed.
This is the code inside CardViewController, the controller brought up after the user touches a cell for details. There are only two labels (term and definition) so the code is pretty scarce here.
override func viewDidLoad() {
super.viewDidLoad()
// Testing
print("new selectedCell: \(selectedCell)")
// Update labels for term and definition
termLabel.text = "Term: \n" + cards[selectedCell]
definitionLabel.text = "Definition: \n" + details[selectedCell]
}
The code inside CardTableViewController where the very last override func is what gives me the selectedCell. I have checked that the number is correct when tapped, it just runs after cardviewcontroller apparently.
This is the code for CardTableViewController, where it is tableview cells of each term from the flashcard listed.
Not to be confused with CardViewController which is the little detail flashcard screen that pops up
import UIKit
var cards = [String]()
var details = [String]()
var newCard:String = ""
var newDetail:String = ""
var study = [String]()
var selectedCell: Int = 0
class CardTableViewController: UITableViewController {
#IBOutlet var createCardButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cards.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cardCell", for: indexPath)
cell.textLabel?.text = cards[indexPath.row]
return cell
}
#IBAction func cancel(segue:UIStoryboardSegue) {
}
#IBAction func create(segue:UIStoryboardSegue) {
let addCard = segue.source as! AddCardViewController
newCard = addCard.term
newDetail = addCard.definition
print("term: \(addCard.term)")
print("definition: \(addCard.definition)")
cards.append(newCard)
details.append(newDetail)
study.append(newCard)
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedCell = indexPath.row
print("selectedCell: ", selectedCell)
}
}
I know it's out of order because of the print statements I put in. Instead, selectedCell should print before new selectedCell. Notice how new selectedCell will be 0 due to initialization (nil if I didn't initialize it) and then is always lagging one cell touch behind what it should be?
the segues for cancel and create are bar button items on the (details of the flashcard screen). They are unwind segues that I followed some online tutorial on for how to create an text field and unwind.
for background on the addCardViewController and unwind segues, this is the code inside that:
class AddCardViewController: UIViewController {
#IBOutlet weak var cardTerm: UITextField!
#IBOutlet weak var cardDefinition: UITextField!
var term:String = ""
var definition:String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "createSegue" {
term = cardTerm.text!
definition = cardDefinition.text!
}
}
Here's the printing results for the cell indexes
new selectedCell: 0
selectedCell: 0
new selectedCell: 0
selectedCell: 1
new selectedCell: 1
selectedCell: 1
Honestly not sure if there's a way to call that function first or if I'm choosing the selectedCell wrong (I got the idea off another post on stack overflow: How to know which cell was tapped in tableView using Swift)
Storyboard for my app. Shows the list of cards tableview controller and the card view controller:
So in my storyboard, I set up two ViewControllers (CardsTableViewController and CardViewController)
The segue in between these two view controllers is called CardSegue and is set up to present modally.
The reuse identifier for the prototype UITableViewCell in CardsTableViewController is CardCell.
This is how the CardsTableViewController looks like:
import UIKit
struct Card {
let term: String
let definition: String
}
class CardsTableViewController: UITableViewController {
var selectedCell: Int = 0
let cards: [Card] = [Card(term: "Привет", definition: "Hello"), Card(term: "Да", definition: "Yes")]
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 cards.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath)
cell.textLabel?.text = cards[indexPath.row].term
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedCell = indexPath.row
performSegue(withIdentifier: "CardSegue", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? CardViewController {
let selectedCard = cards[selectedCell]
vc.card = selectedCard
vc.selectedCell = selectedCell
}
}
}
This is the CardViewController:
import UIKit
class CardViewController: UIViewController {
var card: Card = Card(term: "<Set me>", definition: "<Set me>")
var selectedCell: Int = 0
#IBOutlet weak var termLabel: UILabel!
#IBOutlet weak var definitionLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Testing
print("new selectedCell: \(selectedCell)")
termLabel.text = "Term: \n" + card.term
definitionLabel.text = "Definition: \n" + card.definition
}
}
I created a Card struct which has a term and a definition, both being Strings.
I created an array of two Cards with two Russian words. This is the data we're working with.
In didSelectRowAt indexPath, I have set up the same setting of "selectedCell", which is defined at the top.
Directly after, I call performSegue, which will send the user to the CardViewController, which will display the term and the definition.
The prepare(for segue) method is always called whenever performSegue is called. In the view controller, if you start typing..."prepare(for...." Xcode will probably fill it out for you.
In this method, I get the selected card, and I pass the card to the CardViewController. In this example, I pass selectedCell, but I don't know if it's really necessary, it depends on what you are trying to achieve, I guess.
This is how the two view controllers should be communicating.
Here's some good information about how to pass information from one view controller to the next: See this section: Passing Data Between View Controllers Using Segues
Related
I am trying to create a program on Xcode that allows the user to enter multiple data into a table view through a text field (when a button is clicked). When the data is added I would like it to be stored and not be deleted after the app is closed - for this part I believe that I would have to use NSUserDefaults, however, I am unsure how I would save an array of strings? (I'm only familiar with storing a single string).
This is what my view controller currently looks like.
I have not done much on my view controller at all but this is what it currently has.
import UIKit
class NewViewController: UIViewController {
#IBOutlet weak var text: UITextField!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
Let's tackle this step-by-step...
TL;DR - For your convenience, I've put the final code into a sample project on Github. Feel free to use any or all of the code in your apps. Best of luck!
Step 1 - Conform to UITableView Protocols
"...enter multiple data into a table view..."
At a minimum, UITableView requires you to conform to two protocols in order to display data: UITableViewDelegate and UITableViewDataSource. Interface Builder handles the protocol declaration for you if you use the built-in UITableViewController object, but in your case you cannot use that object because you only want the UITableView to take up a portion of the view. Therefore, you must implement the protocols yourself by adding them to ViewController's signature:
Swift 4
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
}
Step 2 - Implement UITableView Protocol Required Methods
Now that you have the protocols declared, Xcode displays an error until three required methods are implemented inside of your ViewController class. The bare minimum implementation for these methods is:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
You'll implement these methods later, but at this point your code should compile.
Step 3 - Connect UITableView's Protocols to ViewController
Since you are using a standard UITableView object, ViewController is not connected by default to the code you just implemented in the protocol methods. To make a connection, add these lines to viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
Alternatively, you could use the CONTROL + DRAG technique in Interface Builder to connect the delegate and data source from your UITableView to ViewController.
NOTE: In this case, self refers to the ViewController since you're inside of the ViewController class.
Step 4 - UITextField Setup
"...through a text field..."
You previously added an IBOutlet for your UITextField that is connected to Interface Builder, so there is nothing more to do here.
Step 5 - IBAction for the Add Button
(when a button is clicked)."
You need to add an IBAction to your ViewController class and connect it to your Add Button in Interface Builder. If you prefer to write code and then connect the action, then add this method to your ViewController:
#IBAction func addButtonPressed(_ sender: UIButton) {
}
If you use Interface Builder and the CONTROL + DRAG technique to connect the action, the method will be added automatically.
Step 6 - Add an Array Property to Store Data Entries
"...save an array of strings..."
You need an array of strings to store the user's entries. Add a property to ViewController that is initialized as an empty array of strings:
var dataArray = [String]()
Step 7 - Finish Implementing UITableView Protocol Methods
At this point you have everything you need to finish implementing UITableView's protocol methods. Change the code to the following:
//1
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Do nothing
}
//2
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataArray.count
}
//3
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = dataArray[indexPath.row]
return cell
}
In the future, if you want to do something when the user taps a cell, you will want to add code to tableView(_:didSelectRowAt:).
You now create the same number of rows as the number of values in dataArray.
To make this work with Interface Builder, make sure you go to the Attributes Inspector for your UITableViewCell and set the Cell Identifier to Cell. Check out the documentation for more on Dequeuing Cells.
Step 8 - Finish Implementing addButtonPressed(_:)
As suggested in #dani's answer, in the action you need to implement code that appends the user's text to the array, but only if the text is not blank or empty. It is also a good idea to check if dataArray already contains the value you entered using dataArray.contains, depending on what you want to accomplish:
if textField.text != "" && textField.text != nil {
let entry = textField.text!
if !dataArray.contains(entry) {
dataArray.append(entry)
textField.text = ""
}
tableView.reloadData()
}
Step 9 - Persist Data with UserDefaults
"When the data is added I would like it to be stored and not be deleted after the app is closed."
To save dataArray to UserDefaults, add this line of code after the line that appends an entry inside of the addButtonPressed(_:) action:
UserDefaults.standard.set(dataArray, forKey: "DataArray")
To load dataArray from UserDefaults, add these lines of code to viewDidLoad() after the call to super:
if let data = UserDefaults.standard.value(forKey: "DataArray") as? [String] {
dataArray = data
}
Try the following:
Create an array that will store all the text entered via the UITextField (ie. var array = [String]()
In the action of that add button, append the text the user has entered in the text field to the array.
if text.text != "" && !text.text.isEmpty {
// append the text to your array
array.append(text.text!)
text.text = "" // empty the `UITextField`
}
In your tableView methods, make the numberOfRows return array.count and just add a UILabel for your custom UITableViewCell that will display each entered item from the array in a separate cell.
if you want to display your data in tableview you need to implement tableview delegates. add a table view cell with a label on it
#IBOutlet weak var text: UITextField!
#IBOutlet weak var tableView: UITableView!
let NSUD_DATA = "dataarray_store"
var dataArray : NSMutableArray!
var userDefault = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
dataArray = NSMutableArray()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK:- create a button for adding the strings to array and while clicking that button
func onClickButton(){
let string = text.text
dataArray.add(string)
userDefault.set(dataArray, forKey: NSUD_DATA)
}
for getting array stored in userdefault
func getData() -> NSMutableArray?{
if userDefault.object(forKey: NSUD_DATA) != nil{
return userDefault.array(forKey: NSUD_DATA) as! NSMutableArray
}
return nil
}
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
#IBOutlet weak var entertxt: UITextField!
#IBOutlet weak var save: UIButton!
#IBOutlet weak var tableview: UITableView!
var names = [String]()
override func viewDidLoad() {
super.viewDidLoad()
if let data = UserDefaults.standard.object(forKey: "todolist") as?[String]
{
names = data
}
}
#IBAction func submit(_ sender: Any) {
if entertxt.text != "" {
names.append(entertxt.text!)
UserDefaults.standard.set(names, forKey: "todolist")
tableview.reloadData()
entertxt.text = ""
}
else
{
print("data not found")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! myTableViewCell
cell.namelable.text = names[indexPath.row]
return cell
}
I have a "Country" ViewController with two ContainerViews: Side Menu (TocVC) and Data Screen (CountryDetailsVC) on it. Button that controls Side Menu toggling is located in Navigation bar.
Side Menu has a TableView and upon didSelectRowAt indexPath I would like pass its String value back to Data Screen and assign it to a Label on it.
This is what I've tried:
TocVC:
var selectedItem:String = ""
...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedItem = contents[indexPath.row]
let VC = CountryDetailsVC()
VC.labelUpdate(dataFrom: selectedItem)
}
CountryDetailsVC:
#IBOutlet weak var label: UILabel!
...
func labelUpdate(dataFrom: String) {
self.label.text = dataFrom
}
But I'm getting Fatal error: Unexpectedly found nil while unwrapping an Optional value as I understand because TocVC passed data but CountryDetailsVC didn't "refresh" itself and run the function.
What is the right way to do what I'm trying to do?
EDIT: Storyboard screenshot
Storyboard
EDIT1: Updated code.
Country:
let detailsVc = CountryDetailsVC()
TocVC:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedItem = contents[indexPath.row]
Country().detailsVc.labelUpdate(dataFrom: selectedItem)
CountryDetailsVC:
#IBOutlet weak var label: UILabel!
func labelUpdate(dataFrom: String) {
print("dataFrom: \(dataFrom)")
self.label.text = dataFrom
}
The function prints out dataFrom string to the console but crashes on the next line trying to assign dataFrom to label.text.
When I change label: UILabel! to label: UILabel? it doesn't crash but not changing text either.
Maybe it has something to do with this similar situation?
EDIT2: Updated code. Reference to self in segue to TocVC. Still doesn't work.
Country:
let detailsVc = CountryDetailsVC()
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue .destination is TocVC {
let vc = segue.destination as? TocVC
vc?.countryVC = self
}
}
TocVC:
var countryVC: Country?
...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedItem = contents[indexPath.row]
Country().detailsVc.labelUpdate(dataFrom: selectedItem)
CountryDetailsVC:
#IBOutlet weak var label: UILabel!
func labelUpdate(dataFrom: String) {
print("dataFrom: \(dataFrom)")
self.label.text = dataFrom
}
Instead of creating a new instance of CountryDetailsVC in tableView(:didSelectRowAt:), you should store a reference to CountryDetailsVC in your parent view controller in a variable, for example in prepare(for:sender:) of the embed segue and then call your function on that variable later on.
I guess this could be one of my rookie mistakes I couldn't figure out.
I have an app which has a table view. It has text label and detail text label.
When I select a row, I takes me to another story board using segue...all of this works fine except the table view display on my simulator.
detail text label shows up on the simulator shown in this picture circled.
Here is the code I am using to detect cell/row selected. When I comment it out this issue goes away...
What you see in the red circle is gradeselected which is also in the detail text label in the tableview.
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
let gradeselected = String(describing: sgrade)
return [gradeselected]
}
Screenshot of simulator with the issue
Please help in resolving this issue. Let me know if you need any more info.
Xcode 9.1
Swift 4
#Caleb here is my code.
import UIKit
class StudentsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var cellButton: UIButton!
#IBOutlet weak var studentDetailTable: UITableView!
var sname:[String]?
var sgrade:[Int]?
var gradetext = "Grade:"
var sstudentname = ""
override func viewDidLoad() {
super.viewDidLoad()
studentDetailTable.delegate = self
studentDetailTable.dataSource = self
// Do any additional setup after loading the view.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sname!.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = studentDetailTable.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel?.text = sname[indexPath.row] + gradetext + String(sgrade[indexPath.row])
sstudentname = sname![indexPath.row]
cell?.detailTextLabel?.text = String(sgrade![indexPath.row])
cell?.layer.cornerRadius = (cell?.frame.height)!/2
cell?.backgroundColor = UIColor.blue
cell?.textLabel?.textColor = UIColor.white
cell?.layer.borderWidth = 6.0
cell?.layer.cornerRadius = 15
cell?.layer.borderColor = UIColor.white.cgColor
cell?.textLabel?.textColor = UIColor.white
return cell!
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedIndex = tableView.dataSource?.sectionIndexTitles!(for: studentDetailTable)
let indexPath = tableView.indexPathForSelectedRow
let currentCell = tableView.cellForRow(at: indexPath!)!
let scell = currentCell.detailTextLabel!.text!
sstudentname = (currentCell.textLabel?.text)!
}
// - If I comment this section of the code issue goes away.
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
let gradeselected = String(describing: sgrade)
return [gradeselected]
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let myKLVC = segue.destination as! KindergartenLevelViewController
myKLVC.klvstudentname = sstudentname
}
The text in the red circle says [1, 2], which looks like the array that probably holds all the grades, not just the one for a specific cell that we see in the string gradeselected. If you have such an array in your code, look for places where you might be converting it to a string and drawing it. Maybe you did that in an earlier iteration of your code to make sure that the array contained what you thought, or something?
Arrays don't just mysteriously draw themselves on the screen — somewhere, there's some code that causes that to happen. We can't really help you find it because you haven't shown very much of your code, but just knowing what to look for may help you find it yourself.
You can query the selected row via table view's property indexPathForSelectedRow.
The method you have implemented does exactly what you see in the simulator.
Just have a look at the documentation:
property indexPathForSelectedRow: https://developer.apple.com/documentation/uikit/uitableview/1615000-indexpathforselectedrow
func sectionIndexTitles: https://developer.apple.com/documentation/uikit/uitableviewdatasource/1614857-sectionindextitles
I currently have 2 table view controllers. I've added two disclosure indicators on two static cells for marital status and home state (canton). The user clicks on one of both and is taken to another view controller where he makes the appropriate selection.
The code is currently working for marital status. My question is if here I could reuse the second view controller (i.e. the one with the dynamic cells) for the same purpose but utilising a different array (in this case an array with states' names). For me it is clear that I could simply add a new view controller and implement the states' list there. Here is a screenshot of the storyboard:
First View Controller code:
import UIKit
class FirstTableViewController: UITableViewController, DataEnteredDelegate {
#IBOutlet var maritalStatusCell: UITableViewCell!
#IBOutlet var maritalStatusLabel: UILabel!
func userDidEnterInformation(info: String) {
maritalStatusLabel.text = "Marital Status: (\(info))"
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "maritalStatusSegue" {
let sendingVC: SecondTableViewController = segue.destination as! SecondTableViewController
sendingVC.delegate = self
}
}
}
Second View Controller code:
import UIKit
protocol DataEnteredDelegate {
func userDidEnterInformation(info: String)
}
class SecondTableViewController: UITableViewController {
let maritalStatusArray: [String] = ["Single", "Married"]
let cantonArray: [String] = ["ZG", "ZH", "BE", "LU", "AG"]
var delegate: DataEnteredDelegate? = nil
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return maritalStatusArray.count
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if delegate != nil {
let information: String? = tableView.cellForRow(at: indexPath)?.textLabel?.text
delegate!.userDidEnterInformation(info: information!)
dismiss(animated: true, completion: nil)
self.navigationController?.popViewController(animated: true)
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MaritalStatusCell", for: indexPath)
cell.textLabel?.text = maritalStatusArray[indexPath.row]
return cell
}
}
Does is make sense here to use the second table view controller for the states' list as well ? If yes, how can I implement that ? Thanks.
Yes you can use the Same View controller for displaying the Array of your states' names which I think you have declared in cantonArray, what you need to do is declare a bool variable in Second View Controller (In case if you want to manage only two arrays, if you want to manage more arrays then declare an enum). Then in the segue get from which index that segue is fired, you can get the selected indexPath like this
if let indexPath = tableView.indexPathForSelectedRow{
}
Now check the indexPath.row, if it is 0 then you have selected Marital State so you need to show maritalStatusArray array so make the bool variable true if you get indexpath.row = 1 then make that variable false
Now in Second View Controller add a condition as per the bool variable and show the data from that array like this
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MaritalStatusCell", for: indexPath)
if showMaritalArray {
cell.textLabel?.text = maritalStatusArray[indexPath.row]
} else {
cell.textLabel?.text = cantonArray[indexPath.row]
}
return cell
}
This is how you can declare enum
enum SelectedRow {
case MaritalStatus
case States
case ThirdRow
}
var selectedRow = SelectedRow.MaritalStatus
I've spent ages trying to solve this but with no resolve.
I've finally got to a point where I am pulling my data from one one controller and moving it to the destination controller when I unwind segue, however, when the variable is only reloading in the println but not in the tableview.
I'll try to explain this a bit better with my code as it sounds complicated.
I have a label on one controller which when pressed, presents a UISearchController modally. when you select a cell, it dismisses the view with an unwind segue and passes the data from the cell back to the previous controller to change the label of the button.
I set the label.text in a variable at the top of the initial controller like so
var selectedStation = "Search Stations"
here is my shoddy named function which is used to println the variable to see if it works which it does:
func updateStuff() {
println("you selected \(selectedStation)")
tableView.reloadData()
}
and i declare the label text in my cellForRowAtIndexPath like so:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("searchFieldCell", forIndexPath: indexPath) as! searchFieldTableViewCell
cell.backgroundView = UIImageView(image: UIImage(named: "red-full"))
cell.destinationLabel.text = selectedStation
}
then in my UISearchController i have the following to pass that variable back
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
println(stationArray[indexPath.row])
selectedStation = stationArray[indexPath.row]
self.performSegueWithIdentifier("unwindToSet", sender: self)
}
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.destinationViewController .isKindOfClass(SetAlertController) {
var VC = segue.destinationViewController as! SetAlertController
VC.selectedStation = self.selectedStation
VC.updateStuff()
}
}
essentially my controller retrieves the updated variable but doesn't update it in the tableview, it only updates it in the println.
i set up a quick demo project with the following viewcontrollers:
class MainViewController: UIViewController {
#IBOutlet weak var label: UILabel!
#IBAction func unwind(segue: UIStoryboardSegue) {
println("unwinding")
if let sourceViewController = segue.sourceViewController as? ModalViewController {
label.text = sourceViewController.selectedText
}
}
}
tapping on the label results in the modalviewcontroller to show. i set this up in storyboard.
class ModalViewController: UITableViewController {
var selectedText: String?
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)!
selectedText = cell.textLabel?.text
performSegueWithIdentifier("unwindToSet", sender: self)
}
}
everything works as expected! feel free to ask if anything is unclear...
you can find the demo project here: https://www.dropbox.com/sh/u2blzmo3ztaaini/AADq8hOMMS71wvBH1eH4Bz_4a?dl=0