Save user settings using user default swift - ios

I'm working on an application where users can view terms and like or dislike terms.
I'm stack on saving user settings from the table view using user default. I want to save when users click the like or dislike buttons, and when they run the app again the button stays filled
I have a table view cell that contains an outlet for the button and action
import UIKit
class TerminologistTVCell: UITableViewCell {
#IBOutlet weak var btnLike: UIButton!
#IBOutlet weak var btnDislike: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
lconfigureUI()
dconfigureUI()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func lconfigureUI(){
let thumbsdown = UIImage(systemName: "hand.thumbsdown")
let thumbsdownfilled = UIImage(systemName: "hand.thumbsdown.fill")
btnDislike.setImage(thumbsdown, for: .normal)
btnDislike.setImage(thumbsdownfilled, for: .selected)
}
func dconfigureUI(){
let thumbsup = UIImage(systemName: "hand.thumbsup")
let thumbsupfilled = UIImage(systemName: "hand.thumbsup.fill")
btnLike.setImage(thumbsup, for: .normal)
btnLike.setImage(thumbsupfilled, for: .selected)
}
#IBAction func btnLike(_ sender: UIButton) {
sender.isSelected.toggle()
if (sender.isSelected){
btnDislike.isSelected = false
}else{
btnDislike.isSelected = false
}
}
#IBAction func btnDislike(_ sender: UIButton) {
sender.isSelected.toggle()
if (sender.isSelected){
btnLike.isSelected = false
}else{
btnLike.isSelected = false
}
}}
And the ViewController to view the terms and save settings. I tried to save the setting in cellForRow it worked, but when I clicked on the button, it saved for all cells(the button is filled in all cells), not for a cell that I pressed. I want to save for pressed cell
class TerminologistVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var termaArray = MDTerms()
let termName = ""
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return termaArray.arabicTerm.count
}
let userDefaults = UserDefaults.standard
let btnLikePressed = "Likepressed"
let btnDisLikePressed = "DisLikepressed"
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TerminologistTVCell
cell.textLabel?.text = self.termaArray.arabicTerm[indexPath.row]
cell.btnLike.tag = indexPath.row
cell.btnLike.addTarget(self, action: #selector(likeTerm(sender:)), for: .touchUpInside)
cell.btnDislike.tag = indexPath.row
cell.btnDislike.addTarget(self, action: #selector(dislikeTerm(sender:)), for: .touchUpInside)
if userDefaults.bool(forKey: btnLikePressed){
cell.btnLike.isSelected = true
}else{
cell.btnLike.isSelected = false
}
if userDefaults.bool(forKey: btnDisLikePressed){
cell.btnDislike.isSelected = true
}else{
cell.btnDislike.isSelected = false
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
#objc
func likeTerm(sender: UIButton){
print("cell index = \(sender.tag)")
if sender.isSelected{
userDefaults.set(true, forKey: btnLikePressed)
}else{
userDefaults.set(false, forKey: btnLikePressed)
}
}
#objc
func dislikeTerm(sender: UIButton){
print("cell index = \(sender.tag)")
if sender.isSelected{
userDefaults.set(true, forKey: btnDisLikePressed)
}else{
userDefaults.set(false, forKey: btnDisLikePressed)
}
}
My application looks like
ViewController

You are using only two keys in UserDefault which are btnDisLikePressed and btnLikePressed, and clearly you will always get the same values for all cells with all terms. Instead use the termaArray.arabicTerm[indexPath.row] (or in your case cell.textLabel?.text) as the key in UserDefaults.

Related

How do I get the document id by clicking the button on the tableview cell?

I am using a xib file apart from the main storyboard in my view controller for displaying a post item, and there is comment button, upon being clicked it should go to another page where the list of comments related to that post is available. for that I need to pass the documentId of the post as well so that the accurate segue operation could be performed.
I have tried my things by searching google but till now nothing had worked for me.
if any more details are required please let me know
HomeViewController Swift Class
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView:UITableView!
var posts = [Post]()
var db: Firestore!
var postKey:String = ""
private var documents: [DocumentSnapshot] = []
//public var posts: [Post] = []
private var listener : ListenerRegistration!
var detailView: Post?
override func viewDidLoad() {
super.viewDidLoad()
db = Firestore.firestore()
self.navigationController?.navigationBar.isTranslucent = false
tableView = UITableView(frame: view.bounds, style: .plain)
let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
tableView.register(cellNib, forCellReuseIdentifier: "postCell")
tableView.backgroundColor = UIColor(white: 0.90,alpha:1.0)
view.addSubview(tableView)
var layoutGuide:UILayoutGuide!
if #available(iOS 11.0, *) {
layoutGuide = view.safeAreaLayoutGuide
} else {
// Fallback on earlier versions
layoutGuide = view.layoutMarginsGuide
}
tableView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: layoutGuide.topAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
retrieveAllPosts()
//checkForUpdates()
postKey = detailView!._documentId
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
cell.set(post: posts[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let post = self.posts[indexPath.row]
performSegue(withIdentifier: "toCommentsList", sender: indexPath)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//segue.forward(posts, to: segue.destination)
guard let details = segue.destination as? CommentListViewController,
let index = tableView.indexPathForSelectedRow?.row
else {
return
}
// details.detailView = posts[index]
}
//I tried to connect this action to the button in the XIB file but not able to do so.
#IBAction func toCommentsSection(_ sender: Any) {
print(postKey + "hello")
// let postId11 = detailView?._documentId
performSegue(withIdentifier: "toCommentsList", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var vc = segue.destination as! CommentListViewController
vc.postId = postKey
}
}
PostViewCell Class
class PostTableViewCell: UITableViewCell {
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var subtitleLabel: UILabel!
#IBOutlet weak var postTextLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
// profileImageView.layer.cornerRadius = profileImageView.bounds.height / 2
// profileImageView.clipsToBounds = true
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func set(post:Post) {
if let userprofileImagUrl = post._postuserprofileImagUrl,
let imageUrl = URL(string: userprofileImagUrl) {
ImageService.getImage(withURL: imageUrl) { image in
self.profileImageView.image = image
}
}
usernameLabel.text = post._username
postTextLabel.text = post._postContent
subtitleLabel.text = post._postcategory
}
}
In PostTableViewCell create outlet of comment buttons
class PostTableViewCell: UITableViewCell {
#IBOutlet weak var btnComment: UIButton!
now in cellForRowAtIndex do add following line too
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
cell.btnComment.tag = indexPath.row
cell.btnComment.addTarget(self, action: #selector(self. toCommentsSection(sender:)) , for: .touchUpInside)
cell.set(post: posts[indexPath.row])
return cell
}
and in
#IBAction func toCommentsSection(_ sender: Any) {
let commentbutton = sender as! UIButton
let post = posts[commentbutton.tag]
postKey = post.postKey // or what key value it is
print(postKey + "hello")
// let postId11 = detailView?._documentId
performSegue(withIdentifier: "toCommentsList", sender: self)
}

number of radio buttons in a static tableview cell in swift

I have been trying to add 3 radio buttons for gender selection in a static tableviewcell.But am not able to do that.Can any one help to do this.
func setGenderCell(indexPath : IndexPath) -> UITableViewCell {
let cell : SetGenderTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "SetGenderTableViewCell", for: indexPath) as! SetGenderTableViewCell
cell.subject.text = self.profileData[indexPath.row].getName()
cell.genderImage.image = UIImage(named: self.profileData[indexPath.row].getImage())
cell.maleButton.addTarget(self, action: #selector(self.maleGenderSelect), for: .touchUpInside)
cell.femaleButton.addTarget(self, action: #selector(self.femaleGenderSelect), for: .touchUpInside)
cell.othersButton.addTarget(self, action: #selector(self.othersGenderSelect), for: .touchUpInside)
cell.maleButton.tag = 1
cell.femaleButton.tag = 2
cell.othersButton.tag = 3
return cell
}
#objc func maleGenderSelect(){
let cell : SetGenderTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "SetGenderTableViewCell", for: IndexPath) as! SetGenderTableViewCell
cell.maleRadioImage.image = UIImage(named: "")
cell.femaleRadioImage.image = UIImage(named: "")
cell.othersRadioImage.image = UIImage(named: "")
}
#objc func femaleGenderSelect(){
}
#objc func othersGenderSelect(){
}
Reference Image:
Refer this pseudo Code,
Create GenderCellDelegate
protocol GenderCellDelegate : class {
func genderSelected(_ gender : Gender)
}
Enum For gender
enum Gender : Int {
case male = 1, female, other
}
GenderTableViewCell
class GenderTableViewCell: UITableViewCell {
#IBOutlet weak var btnMale : UIButton!
#IBOutlet weak var btnFemale : UIButton!
#IBOutlet weak var btnOther : UIButton!
weak var delegate : GenderCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
// Your can do below from XIB also
// Set buttons images for selcted and normal state
btnMale.setImage(UIImage(named: "radio-on"), for: .selected)
btnFemale.setImage(UIImage(named: "radio-on"), for: .selected)
btnOther.setImage(UIImage(named: "radio-on"), for: .selected)
btnMale.setImage(UIImage(named: "radio-off"), for: .normal)
btnFemale.setImage(UIImage(named: "radio-off"), for: .normal)
btnOther.setImage(UIImage(named: "radio-off"), for: .normal)
// Optional - if required
btnMale.isSelected = true // For default selection
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func btnMaleSelected(_ sender : UIButton) {
self.btnMale.isSelected = true
self.btnFemale.isSelected = false
self.btnOther.isSelected = false
delegate?.genderSelected(.male)
}
#IBAction func btnFemaleSelected(_ sender : UIButton) {
self.btnMale.isSelected = false
self.btnFemale.isSelected = true
self.btnOther.isSelected = false
delegate?.genderSelected(.female)
}
#IBAction func btnOtherSelected(_ sender : UIButton) {
self.btnMale.isSelected = false
self.btnFemale.isSelected = false
self.btnOther.isSelected = true
delegate?.genderSelected(.other)
}
}
Your Controller
class MyController : UIViewController , UITableViewDelegate, UITableViewDataSource, GenderCellDelegate {
:
:
func genderSelected(_ gender: Gender) {
switch gender {
case .male:
print("Male selected")
break
case .female:
print("Female selected")
break
case .other:
print("Other selected")
break
}
// reload tableview row for gender cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let genderCell = tableView.dequeueReusableCell(withIdentifier: "GenderTableViewCell") as! GenderTableViewCell
genderCell.delegate = self
return genderCell
}
}

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

Delegate always nil in tableviewcontroller

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

Why my Tableview is reusing some cells?

I have a Todo list, i have a label and a button in the same cell, when i click the button, change the image button for that cell, but when i scrolled the table view the same button appears on the others cells, it was not to appear in cells that the button were not pressed.
Here is my cellForRowAtIndexPath code
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! TaskTableViewCell
cell.label.text = "Task Number: \(indexPath.row + 1)"
cell.btnFavorite.setImage(UIImage(named: "star"), forState: .Normal)
cell.btnFavorite.setImage(UIImage(named: "star-filled"), forState: .Selected)
cell.btnFavorite.addTarget(self, action: #selector(ListOfTasksViewController.addRemoveFavoriteList), forControlEvents: .TouchUpInside)
return cell
}
func addRemoveFavoriteList(sender : UIButton) {
sender.selected = !sender.selected
}
Custom TableViewCell Class:
import UIKit
class TaskTableViewCell: UITableViewCell {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var btnFavorite: FavoriteButton!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
super.prepareForReuse()
label.text = nil
btnFavorite.selected = false
}
}
View Controller:
import UIKit
class ListOfTasksViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! TaskTableViewCell
cell.label.text = "Task Number: \(indexPath.row + 1)"
cell.btnFavorite.indexPath = indexPath.row
cell.btnFavorite.addTarget(self, action: #selector(ListOfTasksViewController.addRemoveFavoriteList), forControlEvents: .TouchUpInside)
return cell
}
func addRemoveFavoriteList(sender : FavoriteButton) {
if sender.selected {
sender.selected = false
} else {
sender.selected = true
let index = NSIndexPath(forRow: sender.indexPath, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(index) as! TaskTableViewCell
}
}
}
The cells in your table view are reused so as you scroll down, the cells going off screen are being put at the start of the queue before going back onto the screen at a different indexPath. This can cause some issues so you need to override the prepareForReuse method in your custom cell class.
override func prepareForReuse() {
super.prepareForReuse()
label.text = nil
btnFavorite.selected = false
}
you need to add condition in the cellforaRowAtIndexPath.
you need to add flag in Array which track your selection.
then its check in cellforRowAtIndexPath.
for example
button.selected= No
if arrselectedIndexpath containObject:indexPath{
button.selected =yes
}

Resources