Delegate always nil in tableviewcontroller - ios

I am trying to pass data from my tableViewController to my ProfileViewController. so when i clicked cell, then my profile textfield will set the text to the cell that i clicked before.
This is my TableViewController .
protocol TableViewDelegate {
func clickedTableViewCell(info: String)
}
class ProfilePlaceTableViewController : UITableViewController {
var delegate: TableViewDelegate!
#IBOutlet var tableViewProfile: UITableView!
let foods = ["tomato", "red", "rice", "milk", "cheese"]
override func viewDidLoad() {
super.viewDidLoad()
tableViewProfile.delegate = self
tableViewProfile.dataSource = self
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return foods.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = foods[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (tableView.cellForRow(at:indexPath)?.accessoryType == UITableViewCellAccessoryType.checkmark) {
tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCellAccessoryType.none
} else {
tableView.cellForRow(at:indexPath)?.accessoryType = UITableViewCellAccessoryType.checkmark
}
//getting the index path of selected row
let indexPath = tableView.indexPathForSelectedRow
//getting the current cell from the index path
let currentCell = tableView.cellForRow(at: indexPath!)! as UITableViewCell
//getting the text of that cell
let currentItem = currentCell.textLabel!.text
print("currentItem : ", currentItem!)
if (delegate != nil) {
self.delegate?.clickedTableViewCell(info: currentItem!)
self.dismiss(animated: true, completion: nil)
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
}
This is my profileViewController .
class ProfileViewController : UIViewController, TableViewDelegate {
#IBOutlet weak var provinceText: kTextFiledPlaceHolder!
var profilePlaceTableViewController = ProfilePlaceTableViewController()
func clickedTableViewCell(info: String) {
provinceText.text = info
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showProfilePlace" {
let showProfileVc: ProfilePlaceTableViewController = segue.destination as! ProfilePlaceTableViewController
showProfileVc.delegate = self
}
}
override func viewDidLoad() {
let button = UIButton.init(type: .custom)
button.setImage(UIImage.init(named: "ic_hamburger_menu"), for: UIControlState.normal)
button.setTitleColor(UIColor.black, for: .normal)
button.addTarget(self.revealViewController(), action:#selector(SWRevealViewController.revealToggle(_:)), for: UIControlEvents.touchUpInside)
button.sizeToFit()
button.imageEdgeInsets = UIEdgeInsetsMake(4, 4, 4, 4)
let barButton = UIBarButtonItem.init(customView: button)
self.navigationItem.leftBarButtonItem = barButton
self.view.addGestureRecognizer(self.revealViewController().tapGestureRecognizer())
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
provinceText.addTarget(self, action: #selector(provinceClicked(_:)), for: .touchDown)
profilePlaceTableViewController.delegate = self
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func provinceClicked(_ textField: UITextField) {
performSegue(withIdentifier: "showProfilePlace", sender: nil)
}
I have done all this and follow many tutorials but still no solution. Any help would be appreciated. Thank you.

You've declared your delegate (TableViewDelegate) as non-optional, but in the didSelect method, you're using optional chaining - self.delegate?.clickedTableViewCell(info: currentItem!)
Declare your delegate as weak optional property - weak var delegate: TableViewDelegate? = nil to avoid retain cycle.
Delete your profilePlaceTableViewController.delegate = self. You're doing the same in your performSegue method.
And change your protocol declaration to:
protocol TableViewDelegate: class {
func clickedTableViewCell(info: String)
}

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
}

Pass Data (Label) from TableViewCell to another ViewController

I want to pass the Label from a TableViewCell to a ViewController when I click on the Cell. In the end it should be like twitter, that if you click on a cell with a Label you get passed on a detailViewController with the same Label init.
My Code doesn't work as I just get the blanket Label from the Storyboard...
import UIKit
import Firebase
class JobTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var valueToPass:String!
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
// Arvice return to count jobs
return jobs.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
let valueToPass = currentCell.textLabel?.text
print("value: \(valueToPass)")
performSegue(withIdentifier: "toDetails", sender: valueToPass)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "JobCell", for: indexPath) as! JobTableViewCell
let job = jobs[indexPath.row]
cell.job = job
//spacing
cell.contentView.backgroundColor = UIColor.clear
let whiteRoundedView : UIView = UIView(frame: CGRect(x: 10, y: 8, width: self.view.frame.size.width - 20, height: 120))
whiteRoundedView.layer.backgroundColor = CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [0.36, 0.39, 0.40, 1.0])
whiteRoundedView.layer.masksToBounds = false
whiteRoundedView.layer.cornerRadius = 2.0
whiteRoundedView.layer.shadowOffset = CGSize(width: 0, height: 0)
whiteRoundedView.layer.shadowOpacity = 0.0
cell.contentView.addSubview(whiteRoundedView)
cell.contentView.sendSubview(toBack: whiteRoundedView)
cell.emojiLabel.text = cell.emojiString
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDetails" {
let destinationViewController = segue.destination as! JobDetailViewController
destinationViewController.valueToPass = (sender as? String)!
}
}
My Cell:
import UIKit
import Firebase
class JobTableViewCell: UITableViewCell {
#IBOutlet weak var jobLabel: UILabel!
var job: Job! {
didSet {
jobLabel.text = job.text
}
}
}
Job.Swift:
import Foundation
import Firebase
class Job{
var text: String = ""
let ref: DatabaseReference!
init(text: String) {
self.text = text
ref = Database.database().reference().child("jobs").childByAutoId()
}
init(snapshot: DataSnapshot)
{
ref = snapshot.ref
if let value = snapshot.value as? [String : Any] {
text = value["text"] as! String
}
}
func save() {
ref.setValue(toDictionary())
}
func toDictionary() -> [String : Any]
{
return [
"text" : text,
]
}
}
And in my DestinationController:
import UIKit
import Firebase
class JobDetailViewController: UIViewController {
#IBOutlet weak var jobDetail: RoundText!
var valueToPass: String = ""
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
jobDetail.text = valueToPass
}
override func viewDidLoad() {
super.viewDidLoad()
title = "Jobinformation"
}
}
You should not be using cells to store data. You should have a data model that represents the data you are showing in the cells, and you should use the indexPath of the selected cell to look up the data in your data model.
Quick solution:
Change
performSegue(withIdentifier: "yourSegueIdentifer", sender: self) to performSegue(withIdentifier: "yourSegueIdentifer", sender: valueToPass)
2.Your prepare for Segue method should looks like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourSegueIdentifer" {
let destinationViewController = segue.destination as! AnotherViewController
destinationViewController.valueToPass = sender as? String
}
}
On AnotherViewController create var valuteToPass: String = "" and set your label.text = valueToPass
But I think you should not use currentCell.textLabel.text value, instead use the original value. (like if you set your currentCell as cell.textLabel.cell = array[indexPath.row], your valueToPass should be valueToPass = array[indexPath.row])
EDIT:
You use didDeselectRowAt method, instead of didSelectRowAt.
Change func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) to
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Don't use global variable, create it in didSelectRowAt.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
let valueToPass = currentCell.textLabel?.text
print("value: \(valuteToPass)")
performSegue(withIdentifier: "toDetails", sender: valueToPass)
}
On DestinationController:
class DestinationController: UIViewController {
var valuteToPass: String = ""
override func viewDidLoad() {
super.viewDidLoad()
jobLabel.text = valueToPass
}
}
EDIT2
JobTableViewController
delete var valueToPass:String!
Change let valueToPass = jobs[indexPath.row].text instead of let valueToPass = currentCell.textLabel?.text
I checked this change in your code, this will work.
Hi I cant comment but im using #Dris answer and I kept getting this error that says
Could not cast value of type 'UITableViewCell' (0x115464e18) to 'NSString' (0x10fa594c8).
The SIGABRT targets the line destinationViewController.valueToPass = (sender as? String)!
Why is that?
this is basically my code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Determine what to do when a cell in a particular section is selected.
print("did select: \(indexPath.row) ")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
valueToPass = currentCell.textLabel?.text
print("valueToPass: \(String(describing: valueToPass))")
performSegue(withIdentifier: "cellToView", sender: self)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell?
if tableView == self.tableView {
let currentNotif = notificationList[indexPath.row]
cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
cell?.textLabel?.text = currentNotif.notifType
cell?.detailTextLabel?.text = "\(currentNotif.notifTime) \n\(currentNotif.notifContent)"
}
if tableView == self.tableViewAnnounce {
let currentAnnounce = announcementList[indexPath.row]
cell = tableView.dequeueReusableCell(withIdentifier: "cellAnn", for: indexPath) as UITableViewCell
cell?.textLabel?.text = currentAnnounce.annouceType
cell?.detailTextLabel?.text = "\(currentAnnounce.annouceTime) \n\(currentAnnounce.annouceContent)"
}
return cell!
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "cellToView" {
// perform custom segue operation.
let destinationViewController = segue.destination as! ExtendedAnnouncementViewController
destinationViewController.valueToPass = (sender as? String)!
}
}
I'd avoid using a global variable to pass the data to the destination view controller. Defer the lookup until you are ready to pass the data.
And, avoid using force unwrap, it leads to runtime crashes.
Use something like this instead:
let segueIdentifier = "yourSegueIdentifer"
let labelDataSource: [String] = ["SomeText"]
func label(forIndexPath indexPath: IndexPath) -> String? {
let index = indexPath.row
guard labelDataSource.indices.contains(index) else { return nil }
return labelDataSource[index]
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: segueIdentifier, sender: indexPath)
}
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard segue.identifier == segueIdentifier,
let indexPath = sender as? IndexPath,
let destinationViewController = segue.destination as? AnotherViewController else { return }
destinationViewController.valuePassed = label(forIndexPath: indexPath)
}

How do You Inherit a Custom TableViewController For An TableView in a ViewController

So I have a custom SwipeCellTableView class that I inherited from when using UITableViewControllers. Now I want to just use that class for an ib outlet table view controller in a regular View Controller. It is proving to be very difficult and seemingly not worth it anymore. Can this be done?
Here is the superclass which inherits from a TableViewController, I have tried to change it to inherit from a view controller but it just doesn't work out
class SwipeTableViewController: UITableViewController, SwipeTableViewCellDelegate {
var cell: UITableViewCell?
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = 80.0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! SwipeTableViewCell
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
guard orientation == .right else { return nil }
let deleteAction = SwipeAction(style: .destructive, title: "Delete") { action, indexPath in
// handle action by updating model with deletion
self.updateModel(at: indexPath)
}
deleteAction.image = UIImage(named: "delete-icon")
return [deleteAction]
}
func tableView(_ tableView: UITableView, editActionsOptionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions {
var options = SwipeTableOptions()
options.expansionStyle = .destructive
//options.transitionStyle = .reveal
return options
}
func updateModel(at indexPath: IndexPath){
//update data model
print("Item deleted from super class")
}
Here is the View Controller I'm trying to access it from:
class GoalsViewController: UIViewController, SwipeTableViewController {
#IBOutlet weak var categoryTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addCategoryPressed(_ sender: UIButton) {
performSegue(withIdentifier: "showgoalsSeg", sender: self)
}
For reference on how I was using it before when using an actual TableViewController:
class CategoryViewController: SwipeTableViewController {
var categories: Results<Category>? //optional so we can be safe
override func viewDidLoad() {
super.viewDidLoad()
loadCategory()
tableView.rowHeight = 80.0
tableView.separatorStyle = .none
}
//MARK: - Tableview Datasource Methods
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//Only get the count of categories if it's nil, else 1
return categories?.count ?? 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//fetching cell from super view
let cell = super.tableView(tableView, cellForRowAt: indexPath)
cell.textLabel?.text = categories?[indexPath.row].name ?? "No Categories Added Yet"
cell.backgroundColor = UIColor(hexString: categories?[indexPath.row].color ?? "000000")
return cell
}
//MARK: - Tableview Delegate Methods
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "goToItems", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as! ToDoListViewController
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.selectedCategory = categories?[indexPath.row]
}
}
//MARK: - Add New Categories
#IBAction func addButtonPressed(_ sender: Any) {
var textField = UITextField()
let alert = UIAlertController(title: "Add New Category", message: "", preferredStyle: .alert)
let action = UIAlertAction(title: "Add Category", style: .default) { (action) in
let newCategory = Category()
newCategory.name = textField.text!
newCategory.color = UIColor.randomFlat.hexValue()
self.save(category: newCategory)
}
alert.addAction(action)
alert.addTextField { (field) in
textField = field
textField.placeholder = "Add a new category"
}
present(alert, animated: true, completion: nil)
}
func save(category: Category){
let realm = try! Realm()
do {
try realm.write{
realm.add(category)
}
} catch {
print("error saving context")
}
tableView.reloadData()
}
override func updateModel(at indexPath: IndexPath) {
super.updateModel(at: indexPath)
let realm = try! Realm()
if let categoryForDeletion = self.categories?[indexPath.row]{
do{
try realm.write{
realm.delete(categoryForDeletion)
}
} catch {
print("error deleting cell")
}
//tableView.reloadData()
}
}
func loadCategory(){
let realm = try! Realm()
categories = realm.objects(Category.self)
tableView.reloadData()
}
Is this even worth persuing? Or doable?

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()
}
}

how to uncheck uitableview cells using accessory checkmark

i have two sections
1.MapViewController
2.TypesTableViewController
when i run my app and call TypesTableViewController and when it opens it shows all cells selected i want it to be unchecked
please help me and check my code
1.MapViewController
class MapViewController: UIViewController {
#IBOutlet weak var mapCenterPinImage: UIImageView!
#IBOutlet weak var pinImageVerticalConstraint: NSLayoutConstraint!
var searchedTypes = ["bakery", "bar", "cafe", "grocery_or_supermarket", "restaurant"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Types Segue" {
let navigationController = segue.destinationViewController as! UINavigationController
let controller = navigationController.topViewController as! TypesTableViewController
controller.selectedTypes = searchedTypes
controller.delegate = self
}
}
}
// MARK: - TypesTableViewControllerDelegate
extension MapViewController: TypesTableViewControllerDelegate {
func typesController(controller: TypesTableViewController, didSelectTypes types: [String]) {
searchedTypes = controller.selectedTypes.sort()
dismissViewControllerAnimated(true, completion: nil)
}
}
2.TypesTableViewController
protocol TypesTableViewControllerDelegate: class {
func typesController(controller: TypesTableViewController, didSelectTypes types: [String])
}
class TypesTableViewController: UITableViewController {
let possibleTypesDictionary = ["bakery":"Bakery", "bar":"Bar", "cafe":"Cafe", "grocery_or_supermarket":"Supermarket", "restaurant":"Restaurant"]
var selectedTypes: [String]!
weak var delegate: TypesTableViewControllerDelegate!
var sortedKeys: [String] {
return possibleTypesDictionary.keys.sort()
}
// MARK: - Actions
#IBAction func donePressed(sender: AnyObject) {
delegate?.typesController(self, didSelectTypes: selectedTypes)
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return possibleTypesDictionary.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TypeCell", forIndexPath: indexPath)
let key = sortedKeys[indexPath.row]
let type = possibleTypesDictionary[key]!
cell.textLabel?.text = type
cell.imageView?.image = UIImage(named: key)
cell.accessoryType = (selectedTypes!).contains(key) ? .Checkmark : .None
return cell
}
// MARK: - Table view delegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let key = sortedKeys[indexPath.row]
if (selectedTypes!).contains(key) {
selectedTypes = selectedTypes.filter({$0 != key})
} else {
selectedTypes.append(key)
}
tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//toggle checkmark on and off
if tableView.cellForRow(at: indexPath)?.accessoryType == .checkmark {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
else {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
//add animation so cell does not stay selected
tableView.deselectRow(at: indexPath, animated: true)
}
Not sure what you are doing in your code. If you want to uncheck then change below line to
cell.accessoryType = (selectedTypes!).contains(key) ? .Checkmark : .None
to
cell.accessoryType = (selectedTypes!).contains(key) ? . None : . Checkmark
Updated:- second part of the answer to get only checkmark cells,
change as below
#IBAction func donePressed(sender: AnyObject) {
let rowCount = tableView.numberOfRowsInSection(0)
selectedTypes.removeAll()
for var index = 0; index < rowCount; ++index {
let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: index, inSection: 0)) as! YourCell
if cell.accessoryType = .Checkmark{
let key = sortedKeys[index]
selectedTypes.append(key)
}
delegate?.typesController(self, didSelectTypes: selectedTypes)
}
}

Resources