UISegmentedControl in each UITableViewCell of UITableView - ios

I'm trying to implement UISegmentedControl in each dequeueReusableCell UITableViewCell like so:
The Issue: Each TableViewCell is referencing to the same Segmented Control and I'm unable to fetch the state of the control for any cell in particular. As per my understanding, there's only one instance of SegmentedControl that is being initialised and that instance is being shared by all the TableViewCells, and because of that I can't access the unique value of the state for any particular TableViewCell, eg: I'm unable to access what the SegmentControl state is set to for the 3rd cell.
View Controller Code:
import UIKit
import UserNotifications
class MarkAttendanceViewController: UIViewController {
var pickedDate: Date = Date.init()
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.0, *) {
overrideUserInterfaceStyle = .light
}
}
#IBAction func datePicker(_ sender: UIDatePicker) {
pickedDate = sender.date.addingTimeInterval(19800)
let weekDay = Calendar(identifier:.gregorian).component(.weekday, from: pickedDate)
print(weekDay)
updateSubjects(pickedDate)
}
func updateSubjects(_ pickedDate: Date) {
}
}
extension MarkAttendanceViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "subjectCell", for: indexPath) as! SubjectTableViewCell
cell.SessionType.text = "Lecture"
cell.SessionName.text = "Network Security"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
class SubjectTableViewCell: UITableViewCell {
#IBOutlet var SessionType: UILabel!
#IBOutlet var SessionName: UILabel!
#IBOutlet var segmentControlOutlet: UISegmentedControl!
#IBAction func segmentedControlIndex(_ sender: UISegmentedControl) {
print(sender.selectedSegmentIndex)
}
}
Github Link here
Please let me know if there's any more information that I need to provide or if the question isn't clear. TIA

You should set the tag of your segmentControlOutlet to indexPath.row in cellForRowAt:IndexPath method.
Also you must add an action on valueChange event on each of your UISegmentedControl in the same method.
below code might give you some idea:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "subjectCell", for: indexPath) as! SubjectTableViewCell
cell.SessionType.text = "Lecture"
cell.SessionName.text = "Network Security"
// add an action on value change to detect a change in the value of segmented control
cell.segmentControlOutlet.addTarget(self, action: #selector(segmentValueChanged(_:)), for: .valueChanged)
// set the tag property of your segmented control to uniquely identify each segmented control in the value change event
cell.segmentControlOutlet.tag = indexPath.row
return cell
}
and you can distinguish among various instances of UISegmentedControl using the tag property that you set inside the cellForRow method.
#objc func segmentValueChanged(_ sender: UISegmentedControl) {
switch sender.tag {
case 0:
// do something on value changed in segmented control in first cell and so on...
print(sender.tag)
default:
break
}
print(sender.selectedSegmentIndex)
}
Hope this helps

Use this toterial. add UITableViewCell to your project and set UISegment action in custom UITableViewCell

it seems that the root cause of the issue that would like to pass the data between the cell and the VC containing the table and this is done simple by delegate and protocol design pattern as below
you will have a protocol defining the data to be passed between two members as below
protocol SubjectTableViewCellDelegate {
func didSelectSegmentControlCell(cell: SegmentCell)
}
then you will have cell containing the segment control and a delegate var of type SegmentControlDelegate as below
import UIKit
class SubjectTableViewCell: UITableViewCell {
// MARK: Properties
var delegate: SubjectTableViewCellDelegate?
// MARK: IBOutlets
#IBOutlet weak var segmentControl: UISegmentedControl!
// MARK: Life Cycle Methods
override func awakeFromNib() {
super.awakeFromNib()
}
// MARK: IB Actions
#IBAction func segmentControlAction(_ sender: UISegmentedControl) {
delegate?.didSelectSegmentControlCell(cell: self)
}
}
then you will have your VC acting as a delegate of the Segment cell after having each cell delegate to be the VC containing the Table
import UIKit
class MarkAttendanceViewController: UIViewController, SegmentCellDelegate, UITableViewDelegate, UITableViewDataSource {
// MARK: SegmentCellDelegate Methods
func didSelectSegmentControlCell(cell: SegmentCell){
// you will have the cell that contains all the data
/* all your business here */
}
extension MarkAttendanceViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "subjectCell", for: indexPath) as! SubjectTableViewCell
/* remember to have thee delegate of the cell to self as the below line */
cell.delegate = self
cell.SessionType.text = "Lecture"
cell.SessionName.text = "Network Security"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
}
the idea is a general idea imagine there is a button or date picker or any other outlet you should use this pattern to move data between two sides

I would suggest that the answers you have been given, including the accepted answers, are quick fixes that don't actually address the real problem with how you have architected this piece of software. You may not care at this point, but for future readers of the question this may be helpful.
You may have heard of the Model-View-Controller (MVC) architecture that is commonly used when developing for the iOS platform. In the case of your software you have a View -- for simplicity's sake, let's just consider the table view cells as the view in this case. You have a controller -- your MarkAttendanceViewController which implements the UITableViewDataSource and UITableViewDelegate interfaces. The issue, however, is that you don't really have a model for the data you are displaying in the view. In fact, the root of your problem stems from the fact that you are using the view as the model as well, which is problematic because table view cells are reused and the data contained in them can be lost during the cell reuse process if it is not stored somewhere else. If the data is stored in a data model class, you can keep it separate from the table view cells and it will persist through cell reuse.
You have 3 pieces of data associated with each table view cell: The SessionType, the SessionName and the attendance status for the session (ie: Attended, Missed, Mass Bunk or No Lecture). A data model for this could look like this (with an enumerated type to represent the attendance status):
enum AttendanceStatus: Int {
case attended
case missed
case massBunk
case noLecture
}
struct Session {
let name: String
let type: String
var attendanceStatus: AttendanceStatus
}
You may also want to represent type with an enum, but let's keep this simple.
You can instantiate an instance of this data model as follows:
var session = Session(name: "Network Security", type: "Lecture", attendanceStatus: .attended)
Note the var keyword to make it mutable, as you will want to change the attendanceStatus when the UISegmentedControl value changes. Changing this property is done like so:
session.attendanceStatus = .noLecture
To map from your segmented control to AttendanceStatus, you can use the Int raw value for the enum, as follows:
AttendanceStatus(rawValue: segmentedControl.selectedSegmentIndex)
And to map from your data model's attendanceStatus property to a selectedSegmentIndex for your segmented control:
segmentedControl.selectedSegmentIndex = session.attendanceStatus.rawValue
Now in your view controller, you can instantiate an array of Session objects and use that to populate your table view. When a segmented control changes, you can use the indexPath.row of the table view cell for the segmented control in order to find the Session instance in your array of sessions!
(For a more advanced implementation of this, you can also looking into the Model-View-ViewModel (MVVM) architecture which provides an even cleaner way of bidirectional mapping between the data model and the view)

There are multiple way to solve this Problem.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "subjectCell", for: indexPath) as! SubjectTableViewCell
cell.SessionType.text = "Lecture"
cell.SessionName.text = "Network Security"
// add an action on value change to detect a change in the value of segmented control
cell.segmentControlOutlet.addTarget(self, action: #selector(segmentChanged(_:)), for: .valueChanged)
// set the tag property of your segmented control to uniquely identify each segmented control in the value change event
cell.segmentControlOutlet.tag = indexPath.section
return cell
}
Then Find cell based on Segment Control.
#objc func segmentChanged(_ sender: UISegmentedControl) {
if let cell = sender.superview as! UITableViewCell {
let indexPath = tableView.indexPathForCell(cell)
print(indexPath.row)
if indexPath.row == 0 {
print("segment event of cell 0")
}
else if indexPath.row == 1 {
print("segment event of cell 1")
}
}
}
you can also use delegate and Clouser

Related

How to get the indexPath.row when I click a button on a table view cell?

Hello the image above is the UI of my todo list app, now I just want to show the detail of item (First Item, second Item etc) when I click the detail button in the tableviewcell. So in order to get the property of the item, I need to know the indexPath of the row that I just clicked on the detail button.
I have tried some properties of the tableview like didSelectRowAt, or indexPathForSelectedRow, but both not work. For didSelectRowAt user need to click on the row first then click the detail button, and that's not what I want, and the indexPathForSelectedRow is not working for me.
A common, generalized solution for this type of problem is to connect the #IBAction of the button to a handler in the cell (not in the view controller), and then use a delegate-protocol pattern so the cell can tell the table when the button was tapped. The key is that when the cell does this, it will supply a reference to itself, which the view controller can then use to determine the appropriate indexPath (and thus the row).
For example:
Give your UITableViewCell subclass a protocol:
protocol CustomCellDelegate: class {
func cell(_ cell: CustomCell, didTap button: UIButton)
}
Hook up the #IBAction to the cell (not the view controller) and have that call the delegate method:
class CustomCell: UITableViewCell {
weak var delegate: CustomCellDelegate?
#IBOutlet weak var customLabel: UILabel!
func configure(text: String, delegate: CustomCellDelegate) {
customLabel.text = text
self.delegate = delegate
}
#IBAction func didTapButton(_ button: UIButton) {
delegate?.cell(self, didTap: button)
}
}
Obviously, when the cell is created, call the configure method, passing, amongst other things, a reference to itself as the delegate:
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
let text = ...
cell.configure(text: text, delegate: self)
return cell
}
}
Finally, have the delegate method call indexPath(for:) to determine the index path for the cell in question:
extension ViewController: CustomCellDelegate {
func cell(_ cell: CustomCell, didTap button: UIButton) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
// use `indexPath.row` here
}
}
The other approach is to use closures, but again using the same general pattern of hooking the button #IBAction to the cell, but have it call a closure instead of the delegate method:
Define custom cell with closure that will be called when the button is tapped:
class CustomCell: UITableViewCell {
typealias ButtonHandler = (CustomCell) -> Void
var buttonHandler: ButtonHandler?
#IBOutlet weak var customLabel: UILabel!
func configure(text: String, buttonHandler: #escaping ButtonHandler) {
customLabel.text = text
self.buttonHandler = buttonHandler
}
#IBAction func didTapButton(_ button: UIButton) {
buttonHandler?(self)
}
}
When the table view data source creates the cell, supply a handler closure:
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
let text = ...
cell.configure(text: text, buttonHandler: { [weak self] cell in // the `[weak self]` is only needed if this closure references `self` somewhere
guard let indexPath = tableView.indexPath(for: cell) else { return }
// use `indexPath` here
})
return cell
}
}
I personally prefer the delegate-protocol pattern, as it tends to scale more nicely, but both approaches work.
Note, in both examples, I studiously avoided saving the indexPath in the cell, itself (or worse, “tag” values). By doing this, it protects you from getting misaligned if rows are later inserted and deleted from the table.
By the way, I used fairly generic method/closure names. In a real app, you might give them more meaningful names, e.g., didTapInfoButton, didTapSaveButton, etc.) that clarifies the functional intent.
Implement the delegate method tableView(_:accessoryButtonTappedForRowWith:)
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath)
However if you want to navigate to a different controller connect a segue to the accessory view button
If the button is a custom button see my answer in Issue Detecting Button cellForRowAt

Access selected cell section in delegate function in swift

i'm getting data from API service which i'm passing to my tableview and creating section and cell under it. The number of section and cell are dynamic depends upon the data coming from the service. I have a button on my cell. Button name is add. When i click the add button it shows an alerts which contain a tableview. This table view in alert shows only that data which is related to that particular cell under its section. I have created a delegate method for the button in which i'm getting the indexPath.row of that selected button and pass data from my model to the table view inside the alert. When i click the first cell add button it shows everything fine but when i hit add button from section 2 the cashes. What i observed that app is crashing because compiler only gets indexPath.row but it doesn't get information about which section this cell is. How can i get to know my delegate function that which section cell is selection when add button is pressed. This is my code for the delegate function in my cell class,
protocol ResMenuDetailDelegate {
func addOnBtnTapped(tappedIndex : Int)
}
var delegate: ResMenuDetailDelegate?
#IBAction func addBtnTapped(_ sender: Any) {
delegate?.addOnBtnTapped(tappedIndex: addBtn.tag)
}
In my view controller class here i conform the delegate method,
extension RestaurantMenuDetailVC : ResMenuDetailDelegate{
func addOnBtnTapped(tappedIndex: Int) {
print(tappedIndex)
let addonCategory = subCategoryModel![tappedIndex].items[tappedIndex].addonCategory
print(addonCategory as Any)
}
This is my cellForRow table view delegate,
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == resMenuTableView{
let cell = resMenuTableView.dequeueReusableCell(withIdentifier: "detailMenuCell", for: indexPath) as! RestaurantMenuDetailTVC
cell.dishTitleLbl.text = subCategoryModel![indexPath.section].items[indexPath.row].itemName
cell.descriptionLbl.text = subCategoryModel![indexPath.section].items[indexPath.row].itemDescription
cell.priceLbl.text = String(subCategoryModel![indexPath.section].items[indexPath.row].itemPrice)
cell.addBtn.tag = indexPath.row
cell.delegate = self
cell.selectionStyle = .none
cell.backgroundColor = UIColor.clear
return cell
}
You need to send indexpath , the crash because you access the array model section with a row value that exceeds it
func addOnBtnTapped(tappedIndex : IndexPath)
//
extension RestaurantMenuDetailVC : ResMenuDetailDelegate{
func addOnBtnTapped(tappedIndex: IndexPath) {
print(tappedIndex)
let addonCategory = subCategoryModel![tappedIndex.section].items[tappedIndex.row].addonCategory
print(addonCategory as Any)
}
//
#IBAction func addBtnTapped(_ sender: Any) {
delegate?.addOnBtnTapped(tappedIndex:self.myIndexPath)
}
//
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == resMenuTableView{
let cell = resMenuTableView.dequeueReusableCell(withIdentifier: "detailMenuCell", for: indexPath) as! RestaurantMenuDetailTVC
cell.myIndexPath = indexPath
}
//
and declare that var in cell
var myIndexPath:IndexPath!
I think you have to pass two parameters in protocol.
protocol ResMenuDetailDelegate {
func addOnBtnTapped(tappedIndex : Int, button: UIButton)
}
Change the protocol like that so you could have both values for the
row and the section.
protocol ResMenuDetailDelegate {
func addOnBtnTapped(tappedIndexRow: Int,tappedIndexSection: Int )
}
var delegate: ResMenuDetailDelegate?
#IBAction func addBtnTapped(_ sender: Any) {
delegate?.addOnBtnTapped(tappedIndexRow: addBtn.tag,tappedIndexSection: section )
}
Here you can get the section value tableview's delegate method
cellForRowAt.
Add variable in your custom cell for section
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
...
cell.addBtn.tag = indexPath.row
cell.section = indexPath.section
...
...
}

ios - How to get label value from table cell by click button in table cell?

I have an UITableView, in each cell it's have some label and a button. I want to get all label value when I click the button. How to do this? Thank you.
You can do it by closure or delegation
1: Closure
In your tableViewCell class create a variable like this
customObject is the object you passed the tableviewCell to load the data
var cellData: customObject? {
didSet {
// do your loding labels in here
}
}
var clickHandler: ((customObject) -> Void)!
and inside of you action button add this
#IBAction func replyAction(_ sender: Any) {
if let customObject = customObject {
clickHandler(customObject)
}
}
now go to where are you deque the table
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! YourCustomCell
// add this
cell.clickHandler = { customObject in
print("myCell.customObject = \(customObject)")
}
}
this will do the magic
2. Delegation
Create a delegate methode like this
protocol CustomCellDelegate {
func getCustomObject(in cell: CustomCell, withCustomObject object: CustomObject)
}
now in your cell class add delegate variable
var delegate: CustomCellDelegate?
and inside of you action button add this
#IBAction func replyAction(_ sender: Any) {
if let customObject = customObject {
delegate.getCustomObject(in: self, withCustomObject: customObject)
}
}
and now for the last part go to class you implemented the table view and this to where it shows
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! YourCustomCell
// add this
cell.delegate = self
}
and inside of class you should add you delegate method
extension YourClass: CustomCellDelegate {
getCustomObject(in cell: CustomCell, withCustomObject object: CustomObject) {
print("current cell data = \(CustomObject)"
}
}
this will do the job too
Hop this will Helps
Create IBAction method for the button inside the cell custom class and inside it print
print("label text : \(self.lbl.text)")
Or use delegate to send that value to the VC the contains the tableView
First of all. You should have a model object which you are using it to load the values of label. Use
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
to get the index then try getting the value from the model using the index
for example you have an array myArray then you could access the value using myArray[indexPath.row] to get the value. Then save, pass and use it where ever you want. Then implement a delegate method in your custom table cell class passing the indexPath. Then refresh the cell using tableView.reloadRows(at: [IndexPath(item:0,section:0)], with: .fade)

UITableView Duplicate cells (custom cells with textfields)

I have spent days on resolving this issue and after trying much I am asking a question here. I am using a custom UITableViewCell and that cell contains UITextFields. On adding new cells to the table view, the table view behaves abnormal like it duplicates the cell and when I try to edit the textfield of new cell, the textfield of previous cel gets edited too.
The behavior of duplication is as follows: 1st cell is duplicated for 3rd cell. I don't know this is due to reusability of cells but could anyone tell me about the efficient solution?
I am attaching the screenshot of UITableViewCell.
The code for cellForRow is as follows:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : Product_PriceTableViewCell = tableView.dequeueReusableCell(withIdentifier: "product_priceCell") as! Product_PriceTableViewCell
cell.dropDownViewProducts.index = indexPath.row
cell.txtDescription.index = indexPath.row
cell.tfPrice.index = indexPath.row
cell.dropDownQty.index = indexPath.row
cell.tfTotalPrice_Euro.index = indexPath.row
cell.tfTotalPrice_IDR.index = indexPath.row
cell.dropDownViewTotalDiscount.index = indexPath.row
cell.dropDownViewDeposit.index = indexPath.row
cell.tfTotalDeposit_Euro.index = indexPath.row
cell.tfRemaingAfterDeposit_IDR.index = indexPath.row
return cell
}
The issue is the cell is being reused by the UITableView, which is what you want to happen for good scrolling performance.
You should update the data source that supports each row in the table to hold the text the user inputs in the field.
Then have the text field's text property assigned from your data source in cellForRowAt.
In other words, the UITableViewCell is the same instance each time you see it on the screen, and so is the UITextField and therefore so is it's text property. Which means it needs to be assigned it's correct text value each time cellForRowAt is called.
I'm unsure of your code so I have provided an example of how I would do something like what you want:
class MyCell: UITableViewCell {
#IBOutlet weak var inputField: UITextField!
}
class ViewController: UIViewController {
#IBOutlet weak var table: UITableView!
var items = [String]()
fileprivate func setupItems() {
items = ["Duck",
"Cow",
"Deer",
"Potato"
]
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
setupItems()
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// the # of rows will equal the # of items
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// we use the cell's indexPath.row to
// to get the item in the array's text
// and use it as the cell's input field text
guard let cell = tableView.dequeueReusableCell(withIdentifier: "myCell") as? MyCell else {
return UITableViewCell()
}
// now even if the cell is the same instance
// it's field's text is assigned each time
cell.inputField.text = items[indexPath.row]
// Use the tag on UITextField
// to track the indexPath.row that
// it's current being presented for
cell.inputField.tag = indexPath.row
// become the field's delegate
cell.inputField.delegate = self
return cell
}
}
extension ViewController: UITextFieldDelegate {
// or whatever method(s) matches the app's
// input style for this view
func textFieldDidEndEditing(_ textField: UITextField) {
guard let text = textField.text else {
return // nothing to update
}
// use the field's tag
// to update the correct element
items[textField.tag] = text
}
}
I suggest to do the following
class Product_PriceTableViewCell: UITableViewCell {
var indexRow: Int = -1
func configureCell(index: Int) {
cell.dropDownViewProducts.clean()
...
cell.tfRemaingAfterDeposit_IDR.clean()
}
}
where clean is the function to empty de view (depend on the type)
Then in the delegate:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell : Product_PriceTableViewCell = tableView.dequeueReusableCell(withIdentifier: "product_priceCell") as! Product_PriceTableViewCell
cell.configureCell(row: indexPath.row)
return cell
}
As #thefredelement pointed out when the cell is not in the view frame, it is not created. Only when the view is going to appear, it tries to reuse an instance of the cell and as the first is available, the table view uses it but does not reinitialize it. So you have to make sure to clean the data
The rest of the answer is for better coding.

Is it valid to reuse a second view controller with dynamic cells to display elements of a different array in Swift?

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

Resources