Unable to access protocol function in TableViewcell class in swift - swift

I want to access a function present in the protocol in tableviewcell class.But unable to do it. can anyone help me to fix this problem?
protocol updateLcodeCell: class {
func updateAfterSearchApiCall(searchTextArray: [String]?)
}
class PatientFormTableViewController: UIViewController{
var lcodeDelegate: updateLcodeCell?
func callApi(arr: [String]){
lcodeDelegate?.updateAfterSearchApiCall(searchTextArray: arr)}
}
In my cell class
class LcodeTableViewCell: UITableViewCell {
weak var lcodeDelegate: updateLcodeCell?
override func awakeFromNib() {
super.awakeFromNib()
self.lcodeDelegate = self
}
}
extension LcodeTableViewCell: updateLcodeCell{
func updateAfterSearchApiCall(searchTextArray: [String]?) {
searcApiResponseDataArray = searchTextArray
}
}

On your tableView indexPath.row method call your delegate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: yourCellId, for: indexPath) as! YourCustomTableCell
cell.lcodeDelegate = self // here call your delegate
return cell
}

Related

Custom cell did select not call delegate

I have a custom cell named PendingHistoryCell. When did select i get my stake and by indexpath.row value of the id
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let userStakes = self.userStakes
let better_bet_status = userStakes[indexPath.row].bet_status
let deletedOddId = userStakes[indexPath.row]._id
if better_bet_status == "PENDING" {
delegate?.deleteBet(oddId: deletedOddId!)
} else{
}
}
and the protocol is PendingHistoryCell
protocol PendingHistoryCellDelegate {
func deleteBet(oddId: String)
}
And in MyBetsViewContoller i configure the cell
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
if(indexPath.row == 0){
//do some
} else {
let cell: PendingHistoryCell = tableView.dequeueReusableCell(withIdentifier: CellId.MyBets.pendingHistoryCell, for: indexPath) as! PendingHistoryCell
let match = isOnPendingTab ? pendingMatches[indexPath.row-1] : claimedMatches[indexPath.row-1]
//let matchAllData = self.matchData
let userStake = (self.matchData?.bets[indexPath.row-1].stakes)!
//self.fixture = self.matchData?.bets[indexPath.row - 1].fixture
if(self.matchData?.bets[indexPath.row - 1].fixture != nil){
self.fixture = self.matchData?.bets[indexPath.row - 1].fixture!
}
//cell.configure(match: match, isPending: isOnPendingTab, betCount: self.betCount, matchData: matchAllData!, stakes: userStake, fixture:fixture! )
cell.configure(match: match,isPending: isOnPendingTab, betCount: self.betCount, stakes: userStake, fixture: fixture!)
// func configure( isPending: Bool, betCount: Int, stakes:[BT_Stake], fixture: BT_Fixture ) {
return cell
}
}
and in my BetsViewController i called
extension MyBetsViewController: PendingHistoryCellDelegate {
func deleteBet(oddId: String) {
//do some()
}
}
but delegates method does not call.
As others have commented, you need to add the delegate to your tableview cell. To do this, your cell needs the following (in your cell class) :
weak var delegate: PendingHistoryCellDelegate?
To be declared weak (and avoid potential memory leaks), your protocol needs to add : class to its declaration:
protocol PendingHistoryCellDelegate: class {
You can then assign the delegate to your tableview cell in the cellForRow method:
cell.delegate = self
Let me know how you get on!

How to conform a ViewController class to a protocol and set it to "self"

so I have a swift file with 3 different classes in it
import UIKit
class TableRow: UITableViewCell {
#IBOutlet var row: DataRow!
}
class DataRow: UIStackView {
// addnew stackView
var allData: [DataCell]!
}
protocol DataCellDelegate {
func getData(_ personData: [Person])
}
class DataCell: UIStackView {
weak var delegate: DataCellDelegate?
var cellData: [Person]?
let youngerPeople = cellData.filter({$0.age < 16})
delegate.getData(youngerPeople)
}
// and I have this VC Class
import UIKit
class MyViewController: UIViewController, UITableViewDataSource, DataCellDelegate {
func getData(_ personData: [Person]){
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: enter code hereIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableRow
}
}
//how do I get to the delegate on DataCell and set it as self on the
//MyViewController like this
// DataCell.delegate = self
// cos when I put a breakpoint on 1 getData(_ personData: [Person]) nothing happens
In your view controller you would want:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: indexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableRow
for dataCell in cell.row.allData {
dataCell.delegate = self
}
return cell
}
Additionally, it looks like you might want to make your youngerPeople property lazy:
let youngerPeople = {
let data = cellData.filter({$0.age < 16})
delegate.getData(data)
return data
}()

Add target for button in table view cells

I have a table view that its cells have a button in themselves and these buttons should open a view with an unique id. So I need to passing an argument to my buttons but with addTarget property I just can call function without any parameter.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
cell.editButton.addTarget(self, action: #selector(goToEdit(id:)), for: .touchUpInside)
}
func goToEdit(id: String) {
let edit = EditAdViewController(editingAdId: id)
self.navigationController?.pushViewController(edit, animated: true)
}
Is there any way to refer an action with some parameters to a button? Thanks everyone :)
You can try adding delegate functions to your custom UITableViewCell.
For example, I have a button inside this custom tableViewCell:
PickupTableViewCell.swift
import UIKit
protocol PickupTableViewCellDelegate: NSObjectProtocol {
func pickupTableViewCell(userDidTapPickup pickup: Pickup, pickupTableViewCell: PickupTableViewCell)
}
class PickupTableViewCell: UITableViewCell {
// MARK: - Properties
#IBOutlet private weak var label_UserFullName: UILabel!
....
// MARK: - Functions
// MARK: IBAction
#IBAction func pickup(_ sender: Any) {
self.delegate?.pickupTableViewCell(userDidTapPickup: self.pickup, pickupTableViewCell: self)
}
}
Then in I conform my controller via the UITableViewDataSource (cellForRow) and of course implement the delegate function of my tableViewCell.
HomeViewController.swift
// MARK: - UITableViewDataSource
extension HomeViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let pickupTVC = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.pickupTableViewCell)!
pickupTVC.delegate = self
pickupTVC.pickup = self.pickups[indexPath.section]
return pickupTVC
}
}
// MARK: - PickupTableViewCellDelegate
extension HomeViewController: PickupTableViewCellDelegate {
func pickupTableViewCell(userDidTapPickup pickup: Pickup, pickupTableViewCell: PickupTableViewCell) {
// Do something
}
}
Maybe you can try to link your button to a #IBAction and use params[indexPath.row].
To get the indexPath:
var cell = sender.superview() as? UITableViewCell
var indexPath: IndexPath? = yourTableView.indexPath(for: cell!)

Custom delegate method is calling

import UIKit
protocol CustomCellDelegate: class {
func liked(dataDict:NSDictionary,index:NSInteger)
}
class NameImageTextCell: UITableViewCell,UIActionSheetDelegate {
weak var delegateCell: CustomCellDelegate?
#IBAction func btnAction(_ sender: UIButton) {
if delegateCell==nil{
delegateCell?.liked(dataDict: dataNodeDict, index: ItemIndex)
}
}
}
////////
class
FanWallVC:UIViewController,UITableViewDelegate,UITableViewDataSource,
CustomCellDelegate {
#IBOutlet weak var tableView: UITableView!
let objNameImageTextCell = NameImageTextCell()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "NameImageTextCell", bundle: nil),
forCellReuseIdentifier: "NameImageTextCell")
objNameImageTextCell.delegateCell=self
}
func liked(dataDict: NSDictionary, index: NSInteger) {
print("Called")
}
}
When i Click on IBAction(btnAction) in NameImageTextCell, delegateCell is nil,
So liked method is not getting call.
Please help me.
Thanks in advance
You probably should call:
objNameImageTextCell.delegateCell = self
in
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}
so it should look somthing like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "NameImageTextCell", for: indexPath) as! NameImageTextCell
cell.delegateCell = self
//other cell customization
return cell
}

Create custom UITableView class

How i can to create heir of UITableView class that will contain delegate and dataSource methods? I don't want to have dataSource and delegate methods in my ViewController.
You need to create another class for the purpose but first let's see how the ViewController will be.
As you can see the code is sort of self explanatory, I have created a custom class called TableViewDelegate that will be set as a delegate and dataSource of the tableView.
We are passing to TableViewDelegate, the data to be shown in the tableView, and function named didSelectRow that will be called by TableViewDelegate once a row is selected.
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
// data source
var data = [1, 2, 3, 4]
// delegate
var tableViewDelegate: TableViewDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// creating the delegate object and passing the data
tableViewDelegate = TableViewDelegate(data: data)
// passing a function to the delegate object
tableViewDelegate?.didSelectRow = didSelectRow
// setting the delegate object to tableView
tableView.delegate = tableViewDelegate
tableView.dataSource = tableViewDelegate
}
// a function that will be called by the delegate object
// when a row is selected
func didSelectRow(dataItem: Int, cell: UITableViewCell) {
let alert = UIAlertController(title: "Info", message: "\(dataItem) was selected.", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
presentViewController(alert, animated: true, completion: nil)
}
}
The TableViewDelegate that is in charged of everything related of UITableViewDelegate, and UITableViewDataSource protocols.
class TableViewDelegate: NSObject, UITableViewDelegate, UITableViewDataSource {
var data = [Int]()
// variable that holds a stores a function
// which return Void but accept an Int and a UITableViewCell as arguments.
var didSelectRow: ((dataItem: Int, cell: UITableViewCell) -> Void)?
init(data: [Int]) {
self.data = data
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
let text = String(data[indexPath.row])
cell.textLabel?.text = text
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)!
let dataItem = data[indexPath.row]
if let didSelectRow = didSelectRow {
// Calling didSelectRow that was set in ViewController.
didSelectRow(dataItem: dataItem, cell: cell)
}
}
}
Result:
I did this to avoid a long ViewController with a UIPickerViewDelegate/DS. You can simply make a class that conforms to UITableViewDelegate and UITableViewDataSource, instantiate this object in your view controller and assign it as the dataSource and delegate of the table view. For this class to send stuff back to your ViewController, you will have to make a protocol for the VC to conform to and give the class a delegate as well.
I read that this class must inherit from NSObject as the protocols are NSObject protocols, and it throws and error if they don't.
class MyCustomTableViewDel: NSObject, UITableViewDataSource, UITableViewDelegate {
weak var secondaryDelegate: TableViewSecondaryDelegate?
let rowData: [String]
init(dataForRows: [String]) {
rowData = dataForRows
super.init()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return rowData.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
secondaryDelegate?.doSomething(indexPath.row)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
....
return SomeCellForTheTableView
}
}
then make the secondary protocol:
protocol TableViewSecondaryDelegate {
func doSomething(row: Int)
}
then in your ViewController:
class myTableViewSceneController: UIViewController, TableViewSecondaryDelegate {
override func viewDidLoad() {
....
let tableViewDelAndDS = MyCustomTableViewDel(dataForRows: ["row0", "row1"])
tableViewDelAndDS.secondaryDelegate = self
tableView.delegate = tableViewDelAndDS
tableView.dataSource = tableViewDelAndDS
}
func doSomething(row: Int) { ... }
}