how to back data from viewcontroller to tableview use delegate - swift

extension SecondViewController: UITableViewDelegate, UITableViewDataSource, EditContactDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ContactTableView
cell.contact = contacts[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let newVC = NewViewController()
newVC.nameLabel.text = contacts[indexPath.row].name
newVC.delegate = self
newVC.numberPhoneLabel.text = contacts[indexPath.row].numberPhone
newVC.avatarView.image = contacts[indexPath.row].avatar
self.navigationController?.pushViewController(newVC, animated: true)
}
func editContact(name: String, numberPhone: String) {
var contact:Contact?
let nameEdit = name
let numberEdit = numberPhone
contact?.name = nameEdit
contact?.numberPhone = numberEdit
}
}
My data is not updating at tableview even though delegate worksenter image description here

Make variable selectedIndex and set value on did select method
var selectedIndex = 0
func editContact(name: String, numberPhone: String) {
guard selectedIndex > 0 else { return }
contacts[selectedIndex].name = name
contacts[selectedIndex].numberPhone = numberPhone
tableView.reloadData()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let newVC = NewViewController()
newVC.nameLabel.text = contacts[indexPath.row].name
newVC.delegate = self
newVC.numberPhoneLabel.text = contacts[indexPath.row].numberPhone
newVC.avatarView.image = contacts[indexPath.row].avatar
self.navigationController?.pushViewController(newVC, animated: true)
selectedIndex = indexPath.row
}

Related

Disable users to scroll up in tableView?

Similar to tinder, if a user goes down, I don't want them to be able to go back upwards. How do I do this?
I tried the code below, but it keeps running an error: Index out of range.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! FeedTableViewCell
cell.collectionView.delegate = self
cell.collectionView.dataSource = self
//reloading the tableview
let artist: UserModel
artist = self.userList[indexPath.row]
cell.nameLabel.text = artist.name
cell.passionLabel.text = artist.passion
cell.collectionView.reloadData()
if indexPath.row == 1 {
userList.removeFirst()
}
return cell
}
Refer below code,
You need to store last scroll Content Offset of tableview, when user scroll down, refer scrollViewDidScroll method.
#IBOutlet weak var tableView: UITableView!
var lastContentOffsetY:CGFloat = 0.0
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.bounces = false
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "reuse")
self.tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuse")
return cell!
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if(scrollView.contentOffset.y < self.lastContentOffsetY){
self.tableView.setContentOffset(CGPoint(x:scrollView.contentOffset.x, y: self.lastContentOffsetY), animated: false)
}else{
self.lastContentOffsetY = scrollView.contentOffset.y
}
}

Value of type '_' has no member 'count' and 'indexPath'

everyone! I have a problem when I am connecting JSON with the table view. There are two mistakes in the functions:
Value of type 'BalanceStruct?' has no member 'count'
and
Value of type 'BalanceStruct?' has no member 'indexPath'
import UIKit
class BalanceViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var balances: BalanceStruct?
override func viewDidLoad() {
super.viewDidLoad()
ServerManager.shared.getBalanceList(token: UserDefaults.standard.value(forKey: "token") as! String, { (balanceList) in
self.balances = balanceList
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.reloadData()
})
{(error) in print(error)}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return balances.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let balance = balances.indexPath.row
let cell = tableView.dequeueReusableCell(withIdentifier: "BalanceCell", for: indexPath) as! BalancesViewCell
cell.configure(balances: balance)
return cell
}
}
and the problem is in this part:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return balances.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let balance = balances.indexPath.row
let cell = tableView.dequeueReusableCell(withIdentifier: "BalanceCell", for: indexPath) as! BalancesViewCell
cell.configure(balances: balance)
return cell
}
BalanceStruct is a model
struct BalanceStruct: Codable {
let content: [ContentBS]
let pageable: Pageable
let totalPages, totalElements: Int
let last: Bool
let sort: Sort
let numberOfElements: Int
let first: Bool
let size, number: Int
let empty: Bool
}
// MARK: - Content
struct ContentBS: Codable {
let id: Int
let dateCreated: String
let dateUpdated: String?
let name: String
let balance: Int
}
How can I fix it? Thank you!
The table view data source must be an array (or at least a collection type)
var balances = [BalanceStruct]()
Then the data source methods are
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return balances.count // works
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let balance = balances[indexPath.row] // must be index subscription
let cell = tableView.dequeueReusableCell(withIdentifier: "BalanceCell", for: indexPath) as! BalancesViewCell
cell.configure(balances: balance)
return cell
}
However if the content array is supposed to be displayed replace
var balances = [BalanceStruct]()
with
var contentBS = [ContentBS]()
and
self.balances = balanceList
with
self.contentBS = balanceList.content
Now the data source methods are
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return contentBS.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let balance = contentBS[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "BalanceCell", for: indexPath) as! BalancesViewCell
cell.configure(balances: balance)
return cell
}

TableView action per item

I have a tableView like this:
class ViewController: UIViewController {
#IBOutlet var tableView: UITableView!
let names = ["TEXT1", "TEXT2", "TEXT3"]
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewControllerMeer: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let name = names[indexPath.row]
print("You clicked on \(name)")
}
}
extension ViewControllerMeer: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = names[indexPath.row]
let n = names[indexPath.item]
switch n {
case "TEXT1":
print("s1")
case "TEXT2":
print("s2")
case "TEXT3":
print("s3")
default:
break
}
return cell
}
}
It reads the items from the 'let names', So far so good :) I now want to add some actions because now every item will print 'You tapped me'. I figured something out like
override func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if indexPath.row == 0 {
print("cell1")
} else if indexPath.row == 1 {
print("cell2")
} else if indexPath.row == 2 {
print("cell3")
}
}
The only problem is that it generates an error 'Method does not override any method from its superclass'. So I guess this won't work. What would be a good method to do it?
remove the override in front of func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
And you can either to a big if statement or switch statement to do something with the names or you can do something like:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let name = names[indexPath.row]
print("You clicked on \(name)")
switch indexPath.row {
case 0:
//do something
self.shareApp()
case 1:
//do something else
self.writeReview()
default:
break
}
}
I just copied your codes to show you basically if you really want to override tableview functions
class ViewController: UITableViewController {
#IBOutlet var tableView: UITableView!
let names = ["TEXT1", "TEXT2", "TEXT3"]
override func viewDidLoad() {
super.viewDidLoad()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You tapped me!")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = names[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let name = names[indexPath.row]
print("You clicked on \(name)")
}
}

How to navigate to another view controller from datasource class

I have a UIViewController with a UITableView. I have separate class for UITableViewDataSource and UITableViewDelegate. How can I navigate to another view controller when a cell is selected?
class ViewController: UIViewController {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = TableViewDataSource()
}
}
class TableViewDataSource: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//How to push SecondVC from Viewcontroller?
}
}
class TableViewDataSource: UITableViewDataSource, UITableViewDelegate {
var parentViewController : UIViewController?
func init(parentController : UIViewController){
self.parentViewController = parentController
}
// rest of your code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//How to push SecondVC from Viewcontroller?
let storyboard = UIStoryboard(name: "Stroybaordname", bundle: nil)
let secondVC = storyboard.instantiateViewController(withIdentifier: "ViewControllerName")
parentViewController.present(secondVC, animated: true, completion: nil)
}
}
Try this way
If I had to do this I would do it using a separate delegate method. If I am missing the context pardon me.
class ViewController: UIViewController, TableViewDataSourceDelegate {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
let customTableDataSource = TableViewDataSource()
customTableDataSource.delegate = self
// Setting the custom delegate
tableView.delegate = customTableDataSource
}
func cellSelected(at: IndexPath) {
// Navigate from here.
}
}
/// Protocol helps to communicate with the TableViewDataSource to the user of it.
protocol TableViewDataSourceDelegate {
func cellSelected(at: IndexPath)
}
class TableViewDataSource: UITableViewDataSource, UITableViewDelegate {
var delegate: TableViewDataSourceDelegate?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
delegate?.cellSelected(at: indexPath)
}
}
You can create a blocks to access it in your ViewController class.
//MARK:- MODULES
import UIKit
//MARK:- TYPEALIAS
typealias ListCellConfigureBlock = (_ cell : AnyObject? , _ item : AnyObject? , _ indexpath: IndexPath?) -> ()
typealias DidSelectedRow = (_ indexPath : IndexPath) -> ()
typealias ScrollViewDidScroll = (_ scrollView : UIScrollView) -> ()
typealias ViewForHeaderInSection = (_ section : Int) -> UIView?
typealias DidDeselectedRow = (_ indexPath : IndexPath) -> ()
typealias CanEditRowAt = (_ indexPath : IndexPath) -> Bool
typealias CommitEditingStyle = (_ commiteditingStyle: UITableViewCellEditingStyle, _ indexPath : IndexPath) -> ()
typealias HeightForRowAt = (_ indexPath : IndexPath) -> CGFloat
//MARK:- CLASS
class TableViewDataSource: NSObject {
//MARK:- PROPERTIES
var _section: [String]?
var sectionCount: Array<AnyObject>?
var rowCount : Array<AnyObject>?
var cellIdentifier : String?
var tableView : UITableView?
var configureCellBlock : ListCellConfigureBlock?
var aRowSelectedListener : DidSelectedRow?
var ScrollViewListener : ScrollViewDidScroll?
var viewforHeaderInSection : ViewForHeaderInSection?
var headerHeight : CGFloat?
var aRowDeselectedListener : DidDeselectedRow?
var aRowEditListener : CanEditRowAt?
var aRowCommitListener : CommitEditingStyle?
var aRowHeightListener : HeightForRowAt?
init (tableView : UITableView?, cellIdentifier : String?, sectionCount: Array<AnyObject>?, rowCount : Array<AnyObject>? , height : HeightForRowAt? , configureCellBlock : ListCellConfigureBlock? , aRowSelectedListener : #escaping DidSelectedRow,aRowDeselectedListener: #escaping DidDeselectedRow ,aRowCommitListener: #escaping CommitEditingStyle, DidScrollListener : ScrollViewDidScroll?) {
self.tableView = tableView
self.sectionCount = sectionCount
self.rowCount = rowCount
self.cellIdentifier = cellIdentifier
self.aRowHeightListener = height
self.configureCellBlock = configureCellBlock
self.aRowSelectedListener = aRowSelectedListener
self.aRowDeselectedListener = aRowDeselectedListener
self.aRowCommitListener = aRowCommitListener
self.ScrollViewListener = DidScrollListener
}
override init() {
super.init()
}
}
//MARK:- DELEGATE, DATASOURCE
extension TableViewDataSource : UITableViewDelegate , UITableViewDataSource{
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let identifier = cellIdentifier else { fatalError("Cell identifier not provided") }
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: identifier , for: indexPath) as UITableViewCell
cell.selectionStyle = UITableViewCellSelectionStyle.none
if let block = self.configureCellBlock , let item: AnyObject = self.rowCount?[(indexPath as NSIndexPath).row]{
block(cell , item , indexPath as IndexPath?)
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let block = self.aRowSelectedListener{
block(indexPath)
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.rowCount?.count ?? 0
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.sectionCount?.count ?? 0
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard let block = self.aRowHeightListener else { return 0.0 }
return block(indexPath)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
guard let block = viewforHeaderInSection else { return nil }
return block(section)
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self._section?[section]
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return headerHeight ?? 0.0
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if let block = self.ScrollViewListener{
block(scrollView)
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let block = self.aRowDeselectedListener {
block(indexPath)
}
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
guard let block = self.aRowEditListener else { return false }
return block(indexPath)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if let block = self.aRowCommitListener{
block(editingStyle, indexPath)
}
}
}
You can use it like:
//Create a variable:
var dataSource = TableViewDataSource()
fileprivate func setUpDataSource() throws {
DispatchQueue.main.async { [weak self] in
dataSource = TableViewDataSource.init(tableView: tblView, cellIdentifier: CellId.chatUserTVCell.rV, sectionCount: arrSection as Array<AnyObject>, rowCount: arrSearchChatListing , height: { (indexPath) -> CGFloat in
return 80.0
}, configureCellBlock: { (cell, item, indexPath) in
guard let _cell = cell as? ChatUserTableCell, let _item = item as? ChatListing, let row = indexPath?.row else { return }
_cell.chatListing = _item
try? self?.shouldRequestPaging(row: row)
}, aRowSelectedListener: { (indexPath) in
let vc = StoryboardScene.Home.instantiateChatTextController()
try? self?.pushVC(vc)
}, aRowDeselectedListener: { (indexPath) in
debugPrint("Deselected")
}, aRowCommitListener: { (editingStyle, indexPath) in
debugPrint("aRowCommitListener")
}, DidScrollListener: { (scrollView) in
debugPrint("DidScrollListener")
})
tblView.delegate = dataSource
tblView.dataSource = dataSource
tblView.reloadData()
}
}
Hope it helps :)

Hide Cell when the condition is met

Hello StackOverflowers!
I am trying to hide cells when condition is met - in this case when the user survey comment is empty. The data is loaded from Firebase This is what I have tried so far: hiding the cell as well as selecting it. Then follow with heightForRow for selectedRows. But it's not working. Please help! Thank you~~~
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comment.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CommentsTableCell", for: indexPath) as! CommentsCell
let surveyCommentList = self.comment[indexPath.row]
cell.selectionStyle = UITableViewCell.SelectionStyle.none
if surveyCommentList.surveyComment == "" {
cell.isHidden = true
cell.isSelected = true
} else {
cell.surveyCommentText.text = surveyCommentList.surveyComment
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if let selectedRows = tableView.indexPathsForSelectedRows, selectedRows.contains(indexPath) {
return 0
} else {
return 50
}
}
This is the correct implementation :
// Define a new filtered array from your comments that filters empty Comments
let filteredComments = comment.filter({!$0.surveyComment.isEmpty)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredComments.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CommentsTableCell", for: indexPath) as! CommentsCell
let surveyCommentList = self.filteredComments[indexPath.row]
cell.selectionStyle = UITableViewCell.SelectionStyle.none
cell.surveyCommentText.text = surveyCommentList.surveyComment
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}