Not able to select tableview's cell - ios

I'm using Xcode 11.2 and I have a view containing 3 tableviews. They all have outlets to the code and their delegates and datasources are correctly set in the viewDidLoad method.
What happens is that the cell highlights when clicked but then it doesn't remain selected (didSelectRow never gets called).
If I click many times rapidly with the left and right mouse buttons the cell will eventually get selected and the didSelectRow gets called.
Also I noticed that the selection almost always works if I click the cell and at the same time scroll the table a little.
Here some of the code:
#IBOutlet weak var linesTableView: UITableView!
#IBOutlet weak var firstLvlTableView: UITableView!
#IBOutlet weak var secondLvlTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.linesTableView.dataSource = self
self.linesTableView.delegate = self
self.firstLvlTableView.delegate = self
self.firstLvlTableView.dataSource = self
self.secondLvlTableView.dataSource = self
self.secondLvlTableView.delegate = self
if (CLLocationManager.locationServicesEnabled()) {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
self.secondLvlTableView.isHidden = true
self.firstLvlTableView.isHidden = false
self.linesTableView.isHidden = true
fetchData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == linesTableView {
return 0
} else if tableView == firstLvlTableView {
return self.salesAssistantLocalized.count //viewModel.typesOfSale.lists.endIndex
} else if tableView == secondLvlTableView {
return 4 //viewModel.standardTableLevels.lists.endIndex
} else {
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == firstLvlTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "FirstLvlCell", for: indexPath)
cell.textLabel?.text = self.salesAssistantLocalized[indexPath.row]
return cell
} else if tableView == secondLvlTableView {
let cell = tableView.dequeueReusableCell(withIdentifier: "SecondLvlCell", for: indexPath)
cell.textLabel?.text = self.levels[indexPath.row]
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "SaleTypeCell", for: indexPath)
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
printDebug("Did Select Row \(indexPath.row) for table \(tableView)")
if tableView == firstLvlTableView {
if indexPath.row == 0 {
self.secondLvlTableView.isHidden = false
}
}
}

I've found out what is happening.
All the view controllers are extending from a "BaseViewController" that has a tap gesture recognizer for dismissing the keyboard.
That is causing the problem.
I've simply added a Bool to be able to choose if use it or not:
open var useTapGesture: Bool = true
and then wrapped the tap gesture code with this:
if useTapGesture {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(BaseViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
}
This way I can use
useTapGesture = false
in my viewDidLoad method.

Related

using indexPath from table row in outside function swift

New to swift and for a uni project but i have a table view which holds a record of friends details
The user can have the option to edit a friend or delete a friend.
to do this i created a long tap gesture for delete a friend but i am unsure how to pass the indexPath to the function
this is my current layout:
import UIKit
class view_19342665: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var friends: [Friends] = []
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return friends.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "friends", for: indexPath)
cell.textLabel?.adjustsFontSizeToFitWidth = true;
cell.textLabel?.font = UIFont.systemFont(ofSize: 13.0)
cell.textLabel?.text = friends[indexPath.row].displayInfo
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let id = friends[indexPath.row].studentID
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.removeRecord(id: Int(id))
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
let appDelegate = UIApplication.shared.delegate as! AppDelegate
friends = appDelegate.getFriendInfo()
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(sender:)))
tableView.addGestureRecognizer(longPress)
self.tableView.rowHeight = 33.0
}
override var canBecomeFirstResponder: Bool{
return true
}
#objc func handleLongPress(sender:UILongPressGestureRecognizer ){
if sender.state == .began{
// delete user
}
else{
//edit user
}
}
}
right now i can delete the row in the table function.
this is what i am trying to achieve:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let id = friends[indexPath.row].studentID
handleLongPress(id)
}
func handleLongPress(id : Int){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
if sender.state == .began{
appDelegate.removeRecord(id: Int(id))
}
else{
appDelegate.editRecord(id: Int(id))
}
can someone please help me delete a row using the ID on a long tap gesture
The gesture should be added to the table cells inside cellForRowAt not to the table itself
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
cell.contentView.addGestureRecognizer(longPress)
cell.contentView.tag = indexPath.row
Then
#objc func handleLongPress(_ tap:UILongPressGestureRecognizer) {
guard tap.state == .ended && let index = tap.view?.tag else { return }
// use index
}

Swift 5 - make tableview wait until data from api call comes back (using multiple tableviews)

Issue: Fatal error when View is loading. I know the problem is because there is no data available when to table view is trying to load. But, because I am using multiple TableViews in one UI I have to force the cell return in CellForRowAt.
Is there a better way of setting up different data for each TableView?
THANKS FOR THE HELP!
import UIKit
class NewCustomTaskVC: UIViewController {
#IBAction func CancelPressed (_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBOutlet weak var taskTypeSelectionBtn: UIButton!
#IBOutlet weak var FrameSelectionBtn: UIButton!
#IBOutlet weak var AssignSelectionBtn: UIButton!
#IBAction func SelecttaskTypePressed(_ sender: Any) {
if tableViewTaskType.isHidden {
self.tableViewTaskType.isHidden = false
self.tableViewTaskType.rowHeight = 43.5
} else {
self.tableViewTaskType.isHidden = true
}
}
#IBAction func SelectFramePressed(_ sender: Any) {
if tableViewFrame.isHidden {
self.tableViewFrame.isHidden = false
} else {
self.tableViewFrame.isHidden = true
}
}
#IBAction func SelectAssignToPressed(_ sender: Any) {
if tableViewAssignTo.isHidden {
self.tableViewAssignTo.isHidden = false
} else {
self.tableViewAssignTo.isHidden = true
}
}
#IBOutlet weak var tableViewTaskType: UITableView!
#IBOutlet weak var tableViewFrame: UITableView!
#IBOutlet weak var tableViewAssignTo: UITableView!
var cellID = ""
var array = ["String", "Test", "Next","Test 2", "Test 3"]
override func viewDidLoad() {
super.viewDidLoad()
getData()
tableViewTaskType.isHidden = true
tableViewFrame.isHidden = true
tableViewAssignTo.isHidden = true
tableViewTaskType.delegate = self
tableViewFrame.delegate = self
tableViewAssignTo.delegate = self
tableViewTaskType.dataSource = self
tableViewFrame.dataSource = self
tableViewAssignTo.dataSource = self
self.tableViewTaskType.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
self.tableViewFrame.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
self.tableViewAssignTo.register(UITableViewCell.self, forCellReuseIdentifier: "cell3")
}
func getData () {
//dispatchGroup.enter()
var count = 0
APICallBack.getFramesData(completion: { success in
if success == true {
print("frames success")
count += 1
} })
APICallBack.getTaskTypeData { success in
if success == true {
print("task success")
count += 1
}
}
APICallBack.GETUserData(completion: { success in
if success == true {
print("user success")
count += 1
} })
if count == 3{
DispatchQueue.main.async {
self.tableViewTaskType.reloadData()
self.tableViewAssignTo.reloadData()
self.tableViewFrame.reloadData()
print("ALL COMPLETE")
}
}
}
}
extension NewCustomTaskVC : UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count = 1
switch tableView {
case tableViewTaskType:
count = TaskTypeData.typeModel.count
case tableViewFrame:
count = FramesData.framesModel.count
case tableViewAssignTo:
count = CustomerData.customerModel.count
default:
print("none")
return count
}
//return 5
return count
}
**PROBLEM IS HERE
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell?
if tableView == self.tableViewTaskType{
cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
cell!.textLabel!.text = TaskTypeData.typeModel[indexPath.row].TaskTypeName
// cell!.textLabel?.text = array[indexPath.row]
}
if tableView == tableViewFrame{
cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
cell!.textLabel!.text = FramesData.framesModel[indexPath.row].FrameName
// cell!.textLabel?.text = array[indexPath.row]
}
if tableView == self.tableViewAssignTo {
cell = tableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath)
cell!.textLabel!.text = UserData.userModel[indexPath.row].UserFirst
// cell.textLabel?.text = array[indexPath.row]
}
// let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
// cell.textLabel?.text = array[indexPath.row]
return cell!
}
** TO HERE!
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = array[indexPath.row]
print(item)
tableViewTaskType.isHidden = true
}
}
My UI View:
The error I get if I don't force it:
I assume that you want to display an empty "placeholder" cell if the data source array is empty. You need to check explicitly for that condition in your cellForRow function.
As far as co-ordinating the fetch from multiple API endpoints, you can use a DispatchGroup - Some commented code indicates you may have tried this.
override func viewDidLoad() {
super.viewDidLoad()
tableViewTaskType.isHidden = true
tableViewFrame.isHidden = true
tableViewAssignTo.isHidden = true
tableViewTaskType.delegate = self
tableViewFrame.delegate = self
tableViewAssignTo.delegate = self
tableViewTaskType.dataSource = self
tableViewFrame.dataSource = self
tableViewAssignTo.dataSource = self
self.tableViewTaskType.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
self.tableViewFrame.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
self.tableViewAssignTo.register(UITableViewCell.self, forCellReuseIdentifier: "cell3")
getData()
}
func getData () {
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
APICallBack.getFramesData(completion: { success in
if success == true {
print("frames success")
}
dispatchGroup.leave()
})
APICallBack.getTaskTypeData { success in
if success == true {
print("task success")
}
dispatchGroup.leave()
}
APICallBack.GETUserData(completion: { success in
if success == true {
print("user success")
}
dispatchGroup.leave()
})
dispatchGroup.notify {
self.tableViewTaskType.reloadData()
self.tableViewAssignTo.reloadData()
self.tableViewFrame.reloadData()
print("ALL COMPLETE")
}
}
extension NewCustomTaskVC : UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch tableView {
case tableViewTaskType:
return max(1,TaskTypeData.typeModel.count)
case tableViewFrame:
return max(1,FramesData.framesModel.count)
case tableViewAssignTo:
return max(1,CustomerData.customerModel.count)
default:
fatalError("Unexpected table view")
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch tableView {
case self.tableViewTaskType:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
if !TaskTypeData.typeModel.isEmpty {
cell.textLabel!.text = TaskTypeData.typeModel[indexPath.row].TaskTypeName
}
return cell
case tableViewFrame:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
if !FramesData.framesModel.isEmpty {
cell!.textLabel!.text = FramesData.framesModel[indexPath.row].FrameName
}
return cell
case self.tableViewAssignTo:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath)
if !UserData.userModel.isEmpty {
cell!.textLabel!.text = UserData.userModel[indexPath.row].UserFirst
}
return cell
default:
fatalError("Unexpected Tableview")
}
}
you can set tableView.dataSource & tableView.delegate to self when your data is back
There is multiple problems with your code.
1) You call get data before your table view had registered it cells.
So if your API would load data immediately table view will be call dataSource methods
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
but since the
self.tableViewTaskType.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
self.tableViewFrame.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
self.tableViewAssignTo.register(UITableViewCell.self, forCellReuseIdentifier: "cell3")
called in the end of viewDidLoad, your would get crash when you dequeue your cells in cellForAtIndexPath method.
The solution is to move getData call to the end of viewDidLoad method.
2) If you want to display all tables data at one time (when API is complete loading getFramesData, getTaskTypeData and GETUserData) you would need to synchronise this callbacks. You could do this with DispatchGroup.
func getData () {
let apiDispatchGroup = DispatchGroup()
APICallBack.getFramesData { success in
apiDispatchGroup.leave()
}
apiDispatchGroup.enter()
APICallBack.getTaskTypeData { success in
apiDispatchGroup.leave()
}
apiDispatchGroup.enter()
APICallBack.GETUserData { success in
apiDispatchGroup.leave()
}
apiDispatchGroup.enter()
apiDispatchGroup.notify(queue: DispatchQueue.main) {
self.tableViewTaskType.reloadData()
self.tableViewAssignTo.reloadData()
self.tableViewFrame.reloadData()
}
}
3) It's not good idea to use one dataSOurce class for mutltiple UITableView, because of dataSource become god object. The better approach is to use one ContainerViewController that contains three child UITableViewController, and pass data to the childs when data has loaded from the API.
It is perfectly fine to have multiple view controllers in one screen. So I suggest that you create three view controllers, one for each table view. And each table view has its own datasource. Then use a custom container view controller as described here: https://developer.apple.com/documentation/uikit/view_controllers/creating_a_custom_container_view_controller

In swift, how to manage two buttons in same custom tableview cell?

I am trying to manage two buttons in same custom tableview cell.
Added two buttons named Yes and No. If yes button is selected the No button will be inactive and Yes button became active.
Here is the image what I need
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell") as! TableViewCell
cell.yesButton.tag = 101
cell.noButton.tag = 102
cell.yesButton.addTarget(self, action: #selector(buttonClicked(sender:)), for: UIControl.Event.touchUpInside)
cell.noButton.addTarget(self, action: #selector(buttonClicked(sender:)), for: UIControl.Event.touchUpInside)
return cell
}
#objc func buttonClicked(sender: AnyObject) {
let buttonPosition = (sender as AnyObject).convert(CGPoint.zero, to: tableList)
let indexPath = tableList.indexPathForRow(at: buttonPosition)
if sender.tag == 101 {
if indexPath != nil {
print("Cell indexpath = \(String(describing: indexPath?.row))")
}
}
if sender.tag == 102 {
if indexPath != nil {
print("Cell indexpath = \(String(describing: indexPath?.row))")
}
}
}
Create a model to main the state of yesButton and noButton for each tableViewCell, i.e.
class Model {
var isYesSelected = false
var isNoSelected = false
}
Create a custom UITableViewCell with Outlets of yesButton and noButton.
Create a single #IBAction for both the buttons and handle their UI based on which button is tapped.
Also, use a buttonTapHandler to identify the row in which the button is tapped. It will be called everytime a button is tapped. We'll be setting this when creating the instance of TableViewCell in tableView(_:cellForRowAt:).
class TableViewCell: UITableViewCell {
#IBOutlet weak var yesButton: UIButton!
#IBOutlet weak var noButton: UIButton!
var buttonTapHandler: (()->())?
var model: Model?
override func prepareForReuse() {
super.prepareForReuse()
yesButton.backgroundColor = .gray
noButton.backgroundColor = .gray
}
func configure(with model: Model) {
self.model = model
self.updateUI()
}
#IBAction func onTapButton(_ sender: UIButton) {
model?.isYesSelected = (sender == yesButton)
model?.isNoSelected = !(sender == yesButton)
self.updateUI()
}
func updateUI() {
yesButton.backgroundColor = (model?.isYesSelected ?? false) ? .green : .gray
noButton.backgroundColor = (model?.isNoSelected ?? false) ? .green : .gray
}
}
UITableViewDataSource's tableView(_:cellForRowAt:) method goes like,
let numberOfCells = 10
var models = [Model]()
override func viewDidLoad() {
super.viewDidLoad()
(0..<numberOfCells).forEach { _ in
self.models.append(Model())
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfCells
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! TableViewCell
cell.configure(with: models[indexPath.row])
cell.buttonTapHandler = {
print(indexPath.row)
}
return cell
}
To get the totalPoints, count the models with isYesSelected = true, i.e.
let totalPoints = models.reduce(0) { (result, model) -> Int in
if model.isYesSelected {
return result + 1
}
return 0
}
print(totalPoints)
Get that Button using your Tag like below and after that, you can change the value as per you want.
var tmpButton = self.view.viewWithTag(tmpTag) as? UIButton
Simple 3 step process...!!
Define Model Class
Prepare tableView Cell & handle actions
Set up tableView in view controller
Let's start implementation:
1) Define Model Class
In UI, we have a information like question & it's answer (Yes/No). So design model respectively.
//MARK:- Class Declaration -
class Question {
let questionText: String
var answerState: Bool?
init(question: String) {
self.questionText = question
}
}
2. Prepare tableView Cell & handle actions
Create a custom tableView cell with Question Label, Yes Button & No Button. Link that view with respected #IBOutlets & #IBActions.
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var yesButton: UIButton!
#IBOutlet weak var noButton: UIButton!
var question: Question?
var toggle: Bool? {
didSet {
question?.answerState = toggle
//Do buttons operations like...
if let isToggle = toggle {
yesButton.backgroundColor = isToggle ? .green : .gray
noButton.backgroundColor = isToggle ? .gray : .green
} else {
yesButton.backgroundColor = .gray
noButton.backgroundColor = .gray
}
}
}
func prepareView(forQuestion question: Question) {
self.question = question
questionLabel.text = question.questionText
toggle = question.answerState
}
//Yes Button - IBAction Method
#IBAction func yesButtonTapped(_ sender: UIButton) {
toggle = true
}
//No Button - IBAction Method
#IBAction func noButtonTapped(_ sender: UIButton) {
toggle = false
}
}
3. Set up tableView in view controller
class ViewController: UIViewController {
//Prepare questions model array to design our tableView data source
let arrQuestions: [Question] = [Question(question: "Do you speak English?"), Question(question: "Do you live in Chicago?")]
}
//MARK:- UITableView Data Source & Delegate Methods -
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrQuestions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let tableViewCell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell") as? TableViewCell else {
return UITableViewCell()
}
tableViewCell.prepareView(forQuestion: arrQuestions[indexPath.row])
return tableViewCell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80.0
}
}
Create basic tableView and configure dataSource functions
Create tableView cell with two buttons
Create cell class with buttons outlets and actions
Result of this code
Enjoy!

UISwitch state in Tableviewcell resets when user scrolls - Swift

I've searched for a solutions on this issue but none seem to work for my use case.
I have a table inside a viewcontroller and the issue I am facing is that when scrolling the UISwitch state is reset to OFF. I understand table cells are reused, but how do I implement a solution that will restore the state of UISwitch when a user scrolls based on my code below
import UIKit
class StirrViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var mylabel: UILabel!
var myString = String()
#IBAction func stirrBtn(_ sender: AnyObject) {
}
var timeSelected = String()
var selectedTimeArr = [String]()
override func viewDidLoad() {
super.viewDidLoad()
mylabel.text = myString
self.timeSelected = myString
}
func switchChanged(_ sender : UISwitch!){
print("table row switch Changed \(sender.tag)")
print("The switch is \(sender.isOn ? "ON" : "OFF")")
let kValue = (sender.tag + 1)
let keyValue = String(kValue)
if sender.isOn {
recipeSettings.boolStirrSwitch[keyValue] = true
recipeSettings.switchedOnArr.append(keyValue)
} else {
recipeSettings.boolStirrSwitch[keyValue] = false
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let stringNum = Int(self.timeSelected)
recipeSettings.recipeTimeSet2 = stringNum!
return(stringNum)!
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
//here is programatically switch make to the table view
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
switchView.tag = indexPath.row // for detect which row switch Changed
switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
cell.accessoryView = switchView
// Process data displayed in rows(minutes)
let endTime = Int(self.timeSelected)
let startTime = Int(1)
// Recipe time array
let timeArray: [Int] = Array(startTime...endTime!)
let stringTimeArr = timeArray.map{String($0)}
// Save time array to global variable
recipeSettings.recipeTimeSetArr = stringTimeArr
// Create a boolean Array to hold all default false booleans
let defBool: Bool = false
var defBoolArr: [Bool] = []
// Fill the array with the defaults boolean
for _ in 0..<stringTimeArr.count{defBoolArr.append(defBool)}
// Map the array to global dictionary containing the Time in an array and default "false" value
for i in 0..<stringTimeArr.count {
recipeSettings.boolStirrSwitch[stringTimeArr[i]] = defBoolArr[i]
}
// Add the minutes to cell table
cell.textLabel?.text = stringTimeArr[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
As you can see in my code I do save the state of each UI switch in a global variable dictionary. How can I solve the issue of UISwitch changing states based on this code? All help is appreciated. Thanks in advance
var switchState = [String : Bool]()
your recipeSettings.boolStirrSwitch should be decleard like that.
As you are using timeSelected as numberOfRowsInSection as showing
your cell.textLabel from that so you don't need extra stringTimeArr
for that.
All the processing you do in cellForRowAt it will happen again and
again table cells are reused so for setting up data do it in another
function then reload TableView.
Solution for your problem should be look like that.
import UIKit
class StirrViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
//make tableView IBOutlet for reloading data
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var mylabel: UILabel!
var myString = String()
#IBAction func stirrBtn(_ sender: AnyObject) {
}
var timeSelected = String()
var selectedTimeArr = [String]()
override func viewDidLoad() {
super.viewDidLoad()
mylabel.text = myString
self.timeSelected = myString
self.setdefaultSwitchState()
}
//recipeSettings.boolStirrSwitch should be decleard like that
var switchState = [String : Bool]()
//setDeaultSwitchState
func setdefaultSwitchState(){
if let timeSelected = Int(self.timeSelected){
for value in 0..<timeSelected{
switchState["\(value)"] = false
//or
//recipeSettings.boolStirrSwitch["\(value)"] = false
}
}
self.tableView.reloadData()
}
#objc func switchChanged(_ sender : UISwitch!){
print("table row switch Changed \(sender.tag)")
print("The switch is \(sender.isOn ? "ON" : "OFF")")
let kValue = (sender.tag + 1)
let keyValue = String(kValue)
if sender.isOn {
switchState[keyValue] = true
} else {
switchState[keyValue] = false
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
let stringNum = Int(self.timeSelected)
recipeSettings.recipeTimeSet2 = stringNum!
return(stringNum)!
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
//here is programatically switch make to the table view
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
switchView.tag = indexPath.row // for detect which row switch Changed
switchView.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
cell.accessoryView = switchView
cell.textLabel?.text = "\(indexPath.row + 1)"
if let switchState = switchState["\(indexPath.row)"] {
if switchState{
switchView.isOn = true
}else{
switchView.isOn = false
}
}else{
switchView.isOn = false
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}

IOS swift how can I get label text inside a TableView on label tap

I have a TableView that has data inside of it via Labels. When you click the label the Tap registers but now I would like to get the Data of the clicked label and I am having a difficult time getting that done. I have the same functionality working for Buttons for instance this is how I do it for my buttons inside a TableView .
Button Click Event
var locations = [String]()
#IBOutlet weak var Location: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
TableSource.dataSource = self
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Registration_Search", for: indexPath)
cell.Location.setTitle(locations[indexPath.row], for: UIControlState.normal)
cell.Location.addTarget(self, action: #selector(Registration_SearchController.Location_Click(sender:)), for: .touchUpInside)
cell.Location.tag = indexPath.row
return cell
}
func Location_Click(sender: UIButton) {
print(locations[sender.tag])
}
That code above allows me to get the Data of any Button that is clicked . I now try to do the same for the Label but can't get the data that the Label has . This is my Code for the Label and oh the same are the same as above but different ViewController
var locations = [String]()
#IBOutlet weak var location: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
TableSource.dataSource = self
location.isUserInteractionEnabled = true
}
func tapFunctionn(sender: UITapGestureRecognizer)
{
// I would like to get the data for the tapped label here
print("Tapped")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Registration_Search", for: indexPath)
cell.location.text = Locations[indexPath.row]
let tap = UITapGestureRecognizer(target:self, action: #selector(HomePageC.tapFunctionn))
cell.location.addGestureRecognizer(tap)
return cell
}
Again when I click the label it prints Tapped but can't get the actual data. In the Button function I could use Sender.Tag but the UITapGestureRecognizer does not have a Tag method . Any suggestions would be greatly appreciated
You can make something like that:
func tapFunctionn(recognizer: UIPinchGestureRecognizer) {
let view = recognizer.view
let index = view?.tag
print(index)
}
You don't have to use UITapGestureRecognizer. Just use the delegate method. Set the UITableView delegate to your UIViewController and make the class conform to the UITableViewDelegate
For swift 3
override func viewDidLoad() {
super.viewDidLoad()
TableSource.dataSource = self
TableSource.delegate = self
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
//access the label inside the cell
print(cell.label?.text)
//or you can access the array object
//print(Locations[indexPath.row])
}

Resources