This is the first time I'm working with delegate in swift. I've a table view with fixed three number of rows and every row has a seprate .xib for cell.
I'm adjusting the height of each cell based on the data I am getting in the cell. So as the tableView is loaded before and the cells are loaded after so I've defined a protocol in UITableViewCell class.
Above CalenderTimeTableViewCell class I've:
protocol ReloadingTable {
func updateTableView()
}
Inside this class above awakeFromNib() I've: var myDelegate: ReloadingTable? and in the method I'm getting data (using Alamofire) I'm calling self.myDelegate?.updateTableView().
In the viewController in which I've the tableView first of all I extended the class ReloadingTable and in this class I've:
func updateTableView() {
tableView.reloadData()
}
By applying break points the code did get to the self.myDelegate?.updateTableView() but in viewController updateTableView method is not being called.
As #vadian has commented you should assign target class to myDelegate
in cellForRowAt function assign target class to my delegate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! CalenderTimeTableViewCell
cell.myDelegate = self
//Other
}
Related
So I have 2 Views that are shown inside a UIView, based on what is selected on the SegmentViewController. I create dummy data, returning 20 row of a custom cell. This works great.
Everything is fine, till I interact with the TableView.
Bellow is my code:
GoalsViewController.swift
import UIKit
class GoalsViewController: UIViewController {
#IBOutlet weak var goalsTableView: UITableView!
let goalCellIdentifier = "goalCell"
override func viewDidLoad() {
super.viewDidLoad()
goalsTableView.delegate = self
goalsTableView.dataSource = self
goalsTableView.register(UINib(nibName: "GoalsViewCell", bundle: nil), forCellReuseIdentifier: goalCellIdentifier)
goalsTableView.reloadData()
}
}
extension GoalsViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = goalsTableView.dequeueReusableCell(withIdentifier: goalCellIdentifier, for: indexPath) as! GoalsViewCell
cell.goalTitle.text = "aaaaa"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Selected \(indexPath.row)")
}
}
After any of the empty rows is selected, the didSelectRowAt is not called, so the cells are not there at all. I tried to find a solution, but I was only to find issues about empty lists, before being populated.
What could be the reason for the empty tableview?
I might be wrong here but one thing that I've noticed is that you are not implementing a function which sets the height of each cell.
// Specify the height of your cells
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100 // Or your given cell height.
}
So here is my theory: If you are using constraints something is missing and your cell's height can't be identified by constraints alone or you are not using constraints at all thus you must use heightForRowAt function to specify each cell's height.
I will explain what was the issue for people who probably did not know (like me).
So my UITableView is inside a UIView that changes based on what the user is selecting. In total I had 2 different Views that where switching. The reason that it was emptying it was because my parent ViewController, could not access the delegate for UITableView. To fix that, after adding a subview to the UIView, you need also to move the ViewController to the parent controller. In code it goes like this.
// Empty array of UIViewControllers
var views: [UIViewController]!
// Add the UIViewControllers to the array
views = [UIViewController()]
views.append(EventsViewController())
views.append(GoalsViewController())
for view in views {
// Needed to adjust the size of Subview to size of View
view.view.frame = containerView.bounds
// Add the subviews
containerView.addSubview(view.view)
}
// Bring the view in position 1 to the front of the UIView
containerView.bringSubviewToFront(views[1].view)
// Add Views[1] UIViewController as a child to the parent controller
self.addChild(views[1])
views[1].didMove(toParent: self)
// After done with everything with the UIViewController remove it
views[1].removeFromParent()
addChild Apple.com
didMove Apple.com
I have a UITableViewController with custom UITableViewCell, and every cell has an UISwitch inside.
Need to update an information on my table (a string in the header), when any of these switches turn on/off (need to display the number of switches on in the section header).
I'm not confident with iOS and UIKit, but I've already found 2 possibile solutions:
implement a delegate pattern between cell and table controller
write update logic inside the function tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
In the first solution my TableViewController conforms to
protocol TableViewDelegate {
func reloadTable()
}
that update its inner counter of switches on - and update the header section in function tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? - calling
DispatchQueue.main.async{
self.tableView.reloadData()
}
Obviously my custom UITableViewCell has the reference to the delegate TableViewController and call its reloadTable().
The second solution instead is about the possibility to get the information of every cell in the method cellForRowAt indexPath. I've found that this function in not only called when the table has to be drawn, but also when I interact with a component into a cell.
So I need to implement a counting in the function cellForRowAt indexPath? Or the first solution with delegate pattern is a good one?
you should use a delegate in your cell.. can go like this
protocol CellDelegate: class {
func actionDidPressed()
}
then in your cell should use it
class cell: UITableViewCell {
weak var delegate: CellDelegate?
#IBAction func buttonPressed() {
delegate?.actionDidPressed()
}
}
then lastly in your controller you can conform to it
class ViewController: UIViewController {
// in your cellAtIndexPath method after creating cell you can
cell.delegate = self
}
I prefer to make an extension to the View Controller to conform to delegates
extension ViewController: CellDelegate {
func actionDidPressed() {
// add the action you need here
}
}
You can use NSNotification to pass data between different views. You'll need to register the recipient controller by using the addObserver method and use post to send a message. You can refer to this post
According to my other thread, I have a signal SIGABRT error in my code. The code consists of:
A Storyboard with 1 TableView and 1 Table Cell included
A custom Tablecell class (TableViewCell_Prototyp), which is connected to the Storyboard by (strong) IBoutlets.
A View Controller class, which is described in the following.
My ViewController class is connected to 3 super-classes: UIViewController, UITableViewDelegate, UITableViewDataSource. In addition, there are 3 functions implemented. Can somebody find the mistake ?
override func viewDidLoad() {
super.viewDidLoad()
}
i don't know what happens here. It was written by default so it should not cause any errors.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
i just want one table cell to be returned.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell (withIdentifier: "picCell") as! TableViewCell_Prototyp
cell.shoutPic.image = #imageLiteral(resourceName: "Bildschirmfoto 2017-06-05 um 10.11.21")
cell.shoutText.text = "Hallooooooooo"
return cell
}
shoutPic and shoutText is connected to the TableViewCell_Prototype custom class by outlets.
When you have custom table cell classes registered for your tableView, it's better to dequeue them using dequeueReusableCell(withIdentifier:for:), like so:
let cell = tableView.dequeueReusableCell(withIdentifier: "picCell", for: indexPath) as! TableViewCell_Prototyp
If this is all of your code, I would check that your prototype cell's identifier matches "picCell" exactly and that its class is set to TableViewCell_Prototyp
I think #Gereon is right that you need to dequeue with a different method.
Having the class TableViewCell_Prototyp is not enough -- you need to set it to the cell in the Storyboard file. Click on the cell in the storyboard and set it in the Identity tab.
I'm just starting with Swift and xCode, and currently messing around with UITableView, I can't manage to just write 'test' into a table.
I created a UITableViewController in the Storyboard, specified a custom class for it (my swift file below), filled in 'ClientCell' as a reuse identifier of the cell and the code is as follows:
class TableViewController: UITableViewController {
#IBOutlet var clientTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
clientTable.dataSource = self.dataSource;
clientTable.delegate = self;
}
func numberOfRowsInSection(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("ClientCell", forIndexPath: indexPath) as! CustomTableViewCell
cell.tableLabel.text = "test"
return cell
}
}
In the storyboard, I added a 'UILabel' into the prototype cell, and created an outlet for it named 'tableLabel' in the CustomTableViewCell.swift.
I confused by all the side-things I've to consider when doing something as simple as this.
When I run it, the simulator just shows a table with a lot of horizontal lines, but nowhere it says 'test'.
You haven't used the numberOfRowsInSection method.....
Additionally you also need to set the table view's data source and delegate to be the class you are writing these methods in (in case you haven't).
At a bare minimum you need this:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1 // this should really be from your data source
}
If you create a UITableViewController subclass in Xcode the template will have commented-out versions of all the methods you likely will want to fill out.
I have a ViewController that calls (clicking on a button) another View using this function
#IBAction func btnSeeContact(sender: AnyObject) {
self.performSegueWithIdentifier("segueSeeContact", sender: self)
}
and my prototype cell is "linked" to a custom View Controller named ContactsTableViewCell that I have created and it implements:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! ContactsTableViewCell
cell.txtName.text = "test"
cell.txtPhone.text = "1234567890"
return cell
}
When I run the project, the button calls the table, but there is no Cell on it, and I put a breakpoint on those tableView functions and they are not being reached.
What am I missing here that those functions are never being called?
I am adding a new answer since my previous answer was up voted, so I don't want to make massive edits that one, and is still a valid way to fix your issue.
The issue is you have your custom classes confused. In your screen shot you can see that the the Table View Controller is not set to a custom class, it just says Table View Controller. That is the object that needs to get a custom implementation of the UITableViewController class.
Instead you seem to be setting the cell's class to a custom class, and implementing the delegate methods there. You still need a custom class for the table view cell, but it should be a custom class of UITableViewCell.
So your cell class should look something like this:
import UIKit
class YourCustomTableViewCell: UITableViewCell {
#IBOutlet weak var yourLabel1: UILabel!
#IBOutlet weak var yourLabel2: UILabel!
}
You will be given an instance of this cell to configure in cellForIndexPath.
So your Table view controller class should be set to a class that looks like below. The YourTableViewController is were you want to implement all the delegate methods.
Note: if you are using a UITableViewController dragged out from the storyboard, it will already have the tableView, and delegate / data source stuff already wired up for you. You will also notice that you are overriding the delegate methods as the UITableViewController class has default implementations of these. If you are just using a normal view controller, then see my previous answer for more details on how to set that up.
import UIKit
class YourTableViewController: UITableViewController {
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath)
if let cell = cell as? YourCustomTableViewCell {
cell.yourLabel1.text = "some text"
cell.yourLabel2.text = "some other text"
}
return cell
}
}
As others have commented, you really need to provide a little more context.
Here are a few things that might be going wrong, providing more context would confirm or deny this guesses.
First you don't show the numberOfSectionsInTableView method.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 0
}
I think you would need to provide a value other than 0
Secondly, since I don't see override in front of what I am sure you are intending to be UITableViewDelegate methods function calls, that means your view controller is not a UITableViewController. This makes me wonder if you defined this view controller as conforming to the UITableViewDelegate protocol and if you set the table view outlet delegate to self. (or even wired up the UITableView to an outlet)
If you use a plain UIViewController to host a table view you need to do the following:
Wire up your UITableView to an outlet in your view controller
Declare the view controller as conforming to the UITableViewDeleagate (and maybe UITableViewDataSource) protocol
set the table view's outlet delegate (and maybe dataSource) properties to self (the view controller implementing the protocols)
Implement the required methods
So something like this:
class MyTableViewController: UIViewController, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("your PrototypeCell", forIndexPath: indexPath)
// Configure the cell...
return cell
}
}