Action button not working within UITable - ios

I have been through few of these tutorial and I cant seem to call my function via button click. I have followed this guy's tutorial but nothing works.
My tableView currently working just great, all Im doing now is adding a button so I could pass data to another view but my button click is not calling its function.
//class IncomeFeedCell: UITableViewCell:
#IBOutlet var weak button: UIButton!
View Contoller:
// class IncomeFeedVC: UIViewController, UITableViewDelegate, UITableViewDataSource:
// viewDidLoad:
tableView.delegate = self
tableView.dataSource = self
// cellForRowAt indexPath
let cell = self.tableView.dequeueReusableCell(withIdentifier: "IncomeFeedCell") as! IncomeFeedCell
cell.button.tag = indexPath.row
cell.button.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
cell.configureCell(income: income)
return cell
Now the function to call when tapped:
func buttonPressed(){
print("Tapped")
}
Simulator:
Have I missed something simple?
Edit:
Apologies for all who and tried to help and got downvoted because I left out more vital information. All this is inside my viewDidLoad in IncomeFeedVC:
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
DataService.ds.REF_INCOMES.queryOrdered(byChild: "date").observe(.value, with: { (snapshot) in
/**
* Sorting the object before looping over
* Info here: http://stackoverflow.com/questions/41416359/sort-firebase-data-with-queryordered-by-date
*/
guard let incomeSnap = snapshot.value as? [String:AnyObject] else{
return
}
let sorted = incomeSnap.sorted{($0.0.value["date"] as! Double) > ($0.1.value["date"] as! Double)}
for snap in sorted {
if let incomeDict = snap.value as? [String: AnyObject] {
let key = snap.key
let income = Income(incomeId: key, incomeData: incomeDict)
self.incomes.append(income)
}
}
self.tableView.reloadData()
})

My ViewController:
class ViewController: UIViewController , UITableViewDelegate,UITableViewDataSource{
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")! as! TestTableViewCell
cell.bttn.addTarget(self, action: #selector(clickme(sender:)), for: .touchUpInside)
return cell
}
func clickme(sender: UIButton) {
print("cliked")
}
}
My UITableViewCell
import UIKit
class TestTableViewCell: UITableViewCell {
#IBOutlet weak var bttn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Its working fine in my case.
Can you remove the "self" in your
let cell = self.tableView.dequeueReusableCell(withIdentifier: "IncomeFeedCell") as! IncomeFeedCell line.

your button tapped function should be like this:
func buttonPressed(sender: UIButton)
{
let buttonTag = sender.tag// you can check tag like this
}

Can you please try
cell.button.addTarget(self, action: #selector(IncomeFeedVC.buttonPressed(_:)), for: .touchUpInside)
Also below function should be implemented in IncomeFeedVC class
func buttonPressed(_ sender: AnyObject){
print("Tapped")
}

Related

Save user settings using user default swift

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.

How to append to an array on another view controller

I have an array in a tableView that shows that contents of that array, and I am able to append values to the array. the problem is that whenever I go to another page, it automatically empties, but I want the values to stay there. Here is my code for the first view controller:
// AddFoodViewController.swift
// grosseries
//
// Created by Amish Tyagi on 6/2/20.
// Copyright © 2020 grosseries. All rights reserved.
//
import UIKit
class AddFoodViewController: UIViewController {
#IBOutlet weak var foodTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func doneTapped(_ sender: Any) {
}
func transitionToNext() {
let homeViewController = storyboard?.instantiateViewController(identifier: "TableViewController") as? TableViewController
view.window?.rootViewController = homeViewController
view.window?.makeKeyAndVisible()
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "toTableViewController") {
let homeViewController = segue.destination as? TableViewController
homeViewController?.food.append(foodTextField.text!)
view.window?.rootViewController = homeViewController
}
}
}
Here is the code for my second view controller:
// TableViewController.swift
// grosseries
//
// Created by Amish Tyagi on 5/29/20.
// Copyright © 2020 grosseries. All rights reserved.
//
import UIKit
class TableViewController: UIViewController{
#IBOutlet var tableView: UITableView!
var food : [String]! = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view.
}
#IBAction func addItemTapped(_ sender: Any) {
transitionToNext()
}
func transitionToNext() {
let nextViewController = storyboard?.instantiateViewController(identifier: "AddFoodViewController") as? AddFoodViewController
view.window?.rootViewController = nextViewController
view.window?.makeKeyAndVisible()
}
}
extension TableViewController : UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("you tapped me :)")
}
}
extension TableViewController : UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return food.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = food[indexPath.row]
return cell
}
}
Here is a picture of my storyboard layout:
Any Help would be greatly appreciated!
In the storyboard, select your TableViewController storyboard and select Editor->Embed in->Navigation Controller:
Below your tableView (or anywhere else you'd like) add a button with a segue to show the AddFoodViewController.
Now, on your AddFoodViewController add a button to confirm the food you put on textField:
#IBAction func confirmAddedFood(_ sender: Any) {
guard let tableViewVC = navigationController?.viewControllers.first as? TableViewController else { return }
tableViewVC.food.append(foodTextField.text!)
navigationController?.popViewController(animated: true)
}
You don't need the food array on your AddFoodViewController anymore, you still need the one on TableViewController though.
Don't forget to reload the tableView when you go back to it after adding a food, in your TableViewController add:
override func viewWillAppear(_ animated: Bool) {
tableView.reloadData()
}
Your TableViewController:
class TableViewController: UIViewController{
#IBOutlet var tableView: UITableView!
var food: [String] = []
override func viewDidLoad() {
super.viewDidLoad()
// In the case when not using prototype cell.
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
tableView.reloadData()
}
}
extension TableViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return food.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = food[indexPath.row]
return cell
}
}
And FoodViewController:
class AddFoodViewController: UIViewController {
#IBOutlet weak var foodTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func confirmAddedFood(_ sender: Any) {
guard let tableViewVC = navigationController?.viewControllers.first as? TableViewController else { return }
tableViewVC.food.append(foodTextField.text!)
navigationController?.popViewController(animated: true)
}
}
It's not very cool to just give the already done code, but I think in this case is just a silly mistake, whether from you or me.

Access to some values from another class in Swift

I have a TableViewCell class like this:
class CampaignsTableViewCell: UITableViewCell {
#IBOutlet weak var activateButton: UIButton!
#IBOutlet weak var titleCampaignPlaceholder: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setUpButton()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
private func setUpButton(){
activateButton.backgroundColor = .clear
activateButton.layer.cornerRadius = 5
activateButton.layer.borderWidth = 1
activateButton.layer.borderColor = UIColor.blue.cgColor
}
}
And, in another class which is a ViewController I have my UITableView methods:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let rowNumber = indexPath.row
let cellIdentifier = "CampaignTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? CampaignsTableViewCell else {
fatalError("The dequeued cell is not an instance of TableViewCellController.")
}
cell.titleCampaignPlaceholder.text = campaignsArray[rowNumber].campaignName
return cell
}
I need to use my activateButton in my UITableView method in order to access to campaignsArray. I have another method which requieres values from that array, so I need that method is called every time activateButton is pressed from my UITableView.
Any idea ?
Thank you very much
What I like doing in those cases where you have a button inside your UITableViewCell is the following:
Give the cell a closure that is called when tapping on the button like so
class CampaignsTableViewCell: UITableViewCell {
... all your code....
// give your cell a closure that is called when the button is pressed
var onButtonPressed: ((_ sender: UIButton) -> ())?
#IBAction func buttonPressed(sender: UIButton) { // wire that one up in IB
onButtonPressed?(sender)
}
}
and then inside your TableViewController
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! CampaignsTableViewCell
cell.titleCampaignPlaceholder.text = campaignsArray[rowNumber].campaignName
cell.onButtonPressed = { [weak self] sender in
// Do your magic stuff here
}
return cell
Hope that helps
Your cell will get that event, not tableView. What you need to do is:
Create protocol inside your cell:
protocol CampaignsTableViewProtocol{
func actionButtonPressed(row: Int)
}
class CampaignsTableViewCell: UITableViewCell {
#IBOutlet weak var activateButton: UIButton!
#IBOutlet weak var titleCampaignPlaceholder: UILabel!
// keep info about row
var rowIndex: Int = -1
// create delegate that will let your tableView about action button in particular row
var delegate : CampaignsTableViewProtocol?
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setUpButton()
self. activateButton.addTarget(self, action: #selector(self.activatePressed), for: UIControlEvents.touchDown)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func activatePressed(){
self.delegate?.actionButtonPressed(row :rowIndex)
}
private func setUpButton(){
activateButton.backgroundColor = .clear
activateButton.layer.cornerRadius = 5
activateButton.layer.borderWidth = 1
activateButton.layer.borderColor = UIColor.blue.cgColor
}
}
Your tableViewController needs to adopt this protocol:
class MyTableViewController: UITableViewDelegate, UITableViewDataSource, CampaignsTableViewProtocol {
// rest of the code
}
Also, you will need to implement delegate function in your tableViewController:
func actionButtonPressed(row: Int) {
// get campaign you need
let campaign = campaignsArray[row]
// rest of the code
}

Gesturerecogniser for image in tableviewcell in swift3

I'm facing a problem in using UITapGestureRecogniser for an image in tableViewCell. I've created an outlet of object UIImageView in tableViewCell and my requirement is whenever I click on that imageView other image has to be displayed. I've tried the code below, but it didn't work.
Any help would be appreciated!!
Cell
import UIKit
class resultsTableViewCell: UITableViewCell {
#IBOutlet weak var star_selected: UIImageView!
#IBOutlet weak var star_unselected: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
View controller
class resultsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIGestureRecognizerDelegate {
#IBOutlet weak var resultsTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
flightCodeView = FlightCodeView(frame: CGRect.zero)
self.view.addSubview(flightCodeView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultsCellIdentifier", for: indexPath) as! resultsTableViewCell
let image : UIImage = UIImage(named: "star_unselected")!
cell.star_unselected.image = image
let tapGesture = UITapGestureRecognizer(target: self, action: Selector(("ImageSelected")))
cell.star_unselected.addGestureRecognizer(tapGesture)
tapGesture.delegate = self
return cell
}
func ImageSelected(sender: UITapGestureRecognizer? = nil) {
// just creating an alert to prove our tap worked!
let image: UIImage = UIImage(named: "star_selected.png")!
cell.star_selected.image = image
}
}
Check this:
imageView.isUserInteractionEnabled = true
add this code just below tapgesure variable ...
cell.userInteractionEnabled = true
cell.addGestureRecognizer(tapGesture)
I hope this will help..
Add this code in cellForRowAt:
cell.star_unselected.userInteractionEnabled = true
The function will look like :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultsCellIdentifier", for: indexPath) as! resultsTableViewCell
let image : UIImage = UIImage(named: "star_unselected")!
cell.star_unselected.image = image
cell.star_unselected.userInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: Selector(("ImageSelected")))
cell.star_unselected.addGestureRecognizer(tapGesture)
tapGesture.delegate = self
return cell
}

Return number field from Parse into Tableview custom cell

I have a tableview controller with a custom Prototype Cell. The cell contains 2 labels. I am trying to return 2 values from a Parse class. One field is called Notes and is a String value. The other field is called CreditAmount and is a number value. I am having difficulty returning the number value (Credit Amount) in my tableview.
Here is code for tableview controller:
import UIKit
import Parse
import Foundation
class TableViewController: UITableViewController {
var note = [String]()
var credit = [NSInteger]()
var refresher: UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.reloadData()
updateNotes()
self.refresher = UIRefreshControl()
self.refresher.attributedTitle = NSAttributedString(string: "Pull to refresh")
self.refresher.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refresher)
}
func updateNotes() {
let query = PFQuery(className: "Paydown")
query.findObjectsInBackgroundWithBlock({ (objects:[AnyObject]?, error: NSError?) -> Void in
self.note.removeAll(keepCapacity: true)
self.credit.removeAll(keepCapacity: true)
if let objects = objects as? [PFObject] {
for object in objects {
// var noted = object as PFObject
self.note.append(object["Notes"] as! String)
self.credit.append(object["CreditAmount"] as! NSInteger)
}
self.tableView.reloadData()
} else {
//println(error)
}
self.refresher.endRefreshing()
})
}
func refresh() {
updateNotes()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return note.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell
myCell.notesLabel.text = note[indexPath.row]
myCell.amountLabel.text = credit[indexPath.row]
return myCell
}
}
Here is the code for my customer cell:
import UIKit
import Parse
class cell: UITableViewCell {
#IBOutlet weak var notesLabel: UILabel!
#IBOutlet weak var amountLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
The myCell.amountLabel.text = credit[indexPath.row] causes an error: cannot assign a value of type NSInteger (aka int) to a value of type String?. How do I get the number field to work?
Update
myCell.amountLabel.text = credit[indexPath.row]
To be
myCell.amountLabel.text = "\(credit[indexPath.row])"

Resources