why titleForheaderInsection method in different table view controller not work?
I create two table view controllers in one storyboard for my app, with different function, one is SettingsTableViewControlelr, one is CitylistTableViewControlelr, and they should have different section titles.
tableView:titleForHeaderInSection method is used to name section title, but unfortunately only the method in SettingsTableViewControlelr has been appeared correctly in iOS simulator, but the method in CitylistTableViewControlelr is not work, i put a breakpoint on tableView:titleForHeaderInSection method, and find the method even not be called in CitylistTableViewControlelr. Here is my code below:
SettingsTableViewController
import UIKit
class SettingsTableViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, titleForHeaderInSection section:Int) -> String? {
switch section{
case 0:
return"Settings"
default:
return nil
}
}
//the "tableView:titleForHeaderInSection" method in class SettingsTableViewController
//is called and section title appears on simulator.
override func tableView(tableView: UITableView,heightForHeaderInSection section:Int) -> CGFloat {
return 44
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("settingsIdentifier", forIndexPath: indexPath) as! UITableViewCell
return cell
}
}
CitylistTableViewControlelr
import UIKit
class CityListTableViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
func tableView(tableView: UITableView, titleForheaderInsection section: Int) -> String? {
switch section {
case 0:
return "Top Cities"
case 1:
return "Other Cities"
default:
return nil
}
}
//Putting a breakpoint here, and find "tableView:titleForHeaderInSection" method in
//CityListTableViewController is not even been called, thus the section titles, "Top Cities" & "Other Cities",
//do not appear in simulator.I have tried to add "override" keyword before the method, but the
//complier report error says "Method does not override any method from its superclass".
override func tableView(tableView: UITableView,heightForHeaderInSection section:Int) -> CGFloat {
return 44
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section{
case 0:
return 12
case 1:
return 15
default:
return 0
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cityListIdentifier", forIndexPath: indexPath) as! UITableViewCell
switch indexPath.section{
case 0:
cell.textLabel!.text=topCitiesList[indexPath.row]
case 1:
cell.textLabel!.text=otherCitiesList[indexPath.row]
default:
cell.textLabel!.text="unknown"
}
return cell
}
}
My questions are:
Why tableView:titleForHeaderInSection method not be called in CityListTableViewController?
How can I correct my code to make the section title appear on simulator/iPhone respectively?
Have a look at the differences between the two:
In the first view controller where it is being called, the function is being declared like this:
override func tableView(tableView: UITableView, titleForHeaderInSection section:Int) -> String? {
switch section{
Whereas in the one it isn't called it is being declared like this:
func tableView(tableView: UITableView, titleForheaderInsection section: Int) -> String? {
switch section {
You are missing the override declaration. Also, you didn't capitalize the "header" in the second declaration (Thanks for pointing that out Jesper).
Related
I have a simple implementation of a table view with no header. This is the result that I'm going for.
class NavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
self.pushViewController(MyTable(style: .grouped), animated: false)
}
}
class MyTable: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return CGFloat.leastNormalMagnitude
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
assert(false)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
}
Notice that I have an override for viewForHeaderInSection which never gets called which is expected since the height I give is essentially zero.
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
assert(false)
}
When I remove the definition of the above function, then I get a different result. Why does this happen, and is there a way to get the same result without overriding this method?
If a UITableView's delegate implements tableView(_:viewForHeaderInSection:), the calling UITableView switches from assuming you want titles in your section headers to thinking that you want views in your section headers. Once that switch has been made, it checks the delegate's tableView(_:heightForHeaderInSection:) — and since you return (effectively) zero, I'd guess that the table view can lay out without querying the delegate for an actual view.
Keep in mind that making this switch never has to involve calling the view-for-header method. UITableView can check whether its delegate implements the ObjC selector for the method without needing to actually call it, and change its behavior accordingly. That's most likely why your assertion never fires.
The compiler actually throws an error if you don't have the override keyword along with the function.
Overriding declaration requires an 'override' keyword
I have a problem that I want to show a tableview, but separated in sections by the "status" of each item. I know how to do it with a simple string array, but I can't get to make this work with a class (Aluno) array, here's my code so far:
import UIKit
class DeliveriesTVC: UITableViewController {
let sections = ["Delivered", "Not Delivered"]
var studentList: [Array<Student>] = [[], []]
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...5{
studentList[0].append(Student(alunoNome: "Aluno \(i)", alunoImg: "dani_test", alunoStatus: "Delivered"))
}
for i in 6...10{
studentList[1].append(Student(alunoNome: "Aluno \(i)", alunoImg: "dani_test", alunoStatus: "Not Delivered"))
}
self.title = "Deliveries"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cellEntrega = tableView.dequeueReusableCell(withIdentifier: "EntregaCell", for: indexPath) as? EntregaCell {
let entregaCell = studentList[indexPath.section][indexPath.row]
// here i call a function in my TableViewCell class that update the cell itself
cellEntrega.updateAlunoUI(Aluno: entregaCell)
return cellEntrega
} else {
return UITableViewCell()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listaAlunos[section].count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 2
}
}
In the output, i just get the "first section" showing, and without a name, even with me setting the name of each section and the number of sections. I've looked everywhere but i couldn't find a solution.
Your numberOfSections and titleForHeader methods are wrong, it should be
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.sections[section]
}
Additionally, you should return self.sections.count instead of return 2 in numberOfSections being hardcoded as in case you add another object to the array, you will have to change the 2 to whatever elements the array has now.
For your numberOfSectionInTableView function, shouldn't it be override func numberOfSectionsInTableView(in tableView: UITableView) -> Int {
return 2
} with a in in front of the tableView: UITableView?
I don't see where you connect your UITableView's delegate and datasource.
Here is a tutorial to show your about using UITableView.
Take a look at "Basic Table View" - "Step 3: Set the datasource and delegate"
I am not understanding why my app is not compiling. This is the output currently:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var IndexArray = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
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 numberOfSectionsinTableView(tableView: UITableView) -> Int {
return IndexArray.count
}
func tableView(tableView: UITableView, tiltleForHeaderInSection section: Int) -> String? {
return IndexArray[section]
}
func sectionIndexTitlesfortableView (tableView: UITableView) -> [String]? {
return IndexArray
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableCell", for: indexPath as IndexPath) as! TableCell
cell.imgPhoto.image = UIImage(named: "charity")
cell.lblUserName.text! = "User Name"
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}
You are missing to specify a few methods declared in the protocols your class is deriving from.
func tableView(UITableView, cellForRowAt: IndexPath)
Required. Asks the data source for a cell to insert in a particular location of the table view.
func tableView(UITableView, numberOfRowsInSection: Int)
Required. Tells the data source to return the number of rows in a given section of a table view.
At least the two methods above must be declared in your class, otherwise you get the error.
These are just the required methods, but for functioning in the correct way you need to define others. See Apple documentation on UITableViewDataSource protocol
In Swift 3 all method signatures have been changed to:
func numberOfSections(in tableView: UITableView) -> Int { }
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { }
func sectionIndexTitles(for tableView: UITableView) -> [String]? { }
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { }
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
This question already has an answer here:
How can you provide default implementations for UIPageViewControllerDataSource?
(1 answer)
Closed 6 years ago.
I want to reuse the code below
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return UITableViewCell()
}
I define a protocol :
protocol ConfigDetail: class, UITableViewDataSource{}
extension ConfigDetail{
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return UITableViewCell()
}
}
but when i use the protocol with a UIViewController, it always tells me i did not conform to protocol UITableViewDataSource, or i have to add #objc before my protocol. But i have struct variables defined in my protocol, #objc may not help. Any solutions?
If you want to implement these data source methods and reuse them, just define a data source class that implements them. And then rather than implementing the delegate methods in the view controller, instantiate a data source object, keep a strong reference to it, and specify it as the data source for the table view.
For example:
class DataSource: NSObject, UITableViewDataSource {
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
// configure cell here
return cell
}
}
class ViewController: UITableViewController {
let dataSource = DataSource()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = dataSource
}
}
I am getting an error when coding, saying
Type "ViewController" does not conform to protocol "UITableViewDataSource"
Can anyone tell what went wrong with this?
import UIKit
class ViewController: UIViewController, UITableViewDataSource{
let devCourses = [
("Math"),
("Science"),
("English"),
("Computer Programming"),
("Physics")]
func numberOfSectionsInTableview(tableview: UITableView)-> Int {
return 1
}
func tableview(tableView: UITableView, numberOfRowsInSection section: Int) ->Int{
return devCourses.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let (courseTitle) = devCourses[indexPath.row]
cell.textLabel?.text = courseTitle
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This is a common mistake, please make sure you use the correct words. In your case it should be:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return devCourses.count
}
not
func tableview(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return devCourses.count
}
You must use tableView instead of tableview. It is case sensitive
I think you are missing some functions for that are required by the delegate:
The declaration should be changed to include:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
and then you make sure all the required methods for a table are there:
func tableView(tableView:UITableView!, numberOfRowsInSection section:Int) -> Int
and
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
and invoke delegate on ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
yourtableview.dataSource = self
// Do any additional setup after loading the view.
}
Hope this helps