UITableView Section Title Glitch? - ios

I have a view controller with a tableview inside that is grouped. This produces a very weird glitch that causes the sectionTitles to show at the side. I've attached top, trailing, bottom, and leading constraints to the superview for the tableview and I've tested returning UITableViewCell() in cellForRowAtIndexPath to see if it was the cell that was causing the problem, but it still shows it like this.
var sectionTitles = ["Customer Orders", "Unprocessed Orders", "Processed Orders"]
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return sectionTitles.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return sectionTitles
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier(CONSTANTS.CELL_IDENTIFIERS.ORDER_CELL) as! OrderTableViewCell
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Perform segue to order list in future
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 117.0
}

After hours I figured out that I didn't implement this method
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionTitles[section]
}

func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
return sectionTitles
}
If you have only one section you don't put many titles.
If instead you want to give a title for each cell you have to add a label in your customized tableViewCell and in your cellForRowAtIndexPath you have to put something like this (after you have created a NSObject class):
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCellWithIdentifier(CONSTANTS.CELL_IDENTIFIERS.ORDER_CELL) as! OrderTableViewCell
let order = Order[indexPath.row]
cell.yourTitleLabel.text = order.title
return cell
}

Related

UITableView Section Index Out Of Bounds but it's not really out of bounds

Whenever I run the app, the tableView has no data, waiting for user to input. The problem is that if the numberOfSections is 1, it works just fine, but when I change it to 2 it crashes because Index out of range
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "expenseCell") as? ExpenseCell else { return UITableViewCell() }
let budget = userBudget[indexPath.section][indexPath.row]
cell.delegate = self
cell.configureCell(budget: budget)
return cell
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.none
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return userBudget[section].count // <- Crash here
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Practice with Sections \(section)"
}
It is because you are accessing index 1 of userBudget while i assume it contains 0 index only.
This crash happens cause your array userBudget, don't has two elements at the moment you try access his second position.
You must guard that userBudget has two elements on minimium...
You should that you must to assign value to userBudget on your ViewDidLoad.
You are saying that you will have two section to your tableView's delegate, but you have an array which contains only one array. Basically when you try to reach userBadget[1] in your numberOfRowsInSection function and it crashes because it doesn't exist.
Replace
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
With
func numberOfSections(in tableView: UITableView) -> Int {
return userBudget.count
}

How to use the heightForRowAtIndexPath method?

I am trying to use the heightForRowAtIndexPath method in my UITableViewController. But when I try to override the method it says that it does not override any methods from its superclass.
Googling has led me to protocols, which seem to potentially be some part of the puzzle, but I'm still trying to understand how to use a protocol to use this method.
Any help would be greatly appreciated. Here's the code: (the problem method is at the very bottom)
import UIKit
import Firebase
class FruitsTableViewController: UITableViewController {
let rootRef = FIRDatabase.database().reference()
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 15
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LabelCell", for: indexPath)
let busRef = rootRef.child("buses")
busRef.observeSingleEvent(of: .value, with: {(snapshot) in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
let bus = snapshots[Int(indexPath.row)].key
let busval = snapshots[Int(indexPath.row)].value as! String
cell.textLabel?.text = "Bus \(bus) ------- \(busval)"
}
})
return cell
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section \(section)"
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 40.0
}
}
You can either set a static height:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
if indexPath.section == 0 {
return 50
} else {
return 120
}
}
Or use automatic dimension, with resizes every cell automatically according to its content:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Use following code
func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return 50.0
}
You have:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
Replace it with:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
[I'm not sure whether you need the override but if you do the compiler will tell you so and you can put it back in.]
Remove override and the code should work. This is an optional protocol method--if you don't specify it, it will calculate the cell's height from the cell's view based on autolayout or the height set in prototype or static cells.
Remove "override" and the following code should work
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 75.0
}

iOS Swift - Show Contacts in TableView using UILocalizedIndexedCollation

// MARK: UITableViewDelegate
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String {
print("titleForHeaderInSection: \(collation.sectionTitles[section])")
return collation.sectionTitles[section]
}
override func sectionIndexTitlesForTableView(tableView: UITableView) -> [String] {
print("sectionIndexTitlesForTableView: \(collation.sectionIndexTitles)")
return collation.sectionIndexTitles
}
override func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int {
print("sectionForSectionIndexTitle: \(sections.count)")
return collation.sectionForSectionIndexTitleAtIndex(index)
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (self.results.count > 0) ? self.results.count : 0
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
let numberOfSections = UILocalizedIndexedCollation.currentCollation().sectionTitles.count
print("numberOfSections: \(numberOfSections)")
return numberOfSections
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("contactscell") as UITableViewCell!
let label = cell.viewWithTag(1) as? UILabel
label?.text = self.results[indexPath.row].givenName
return cell
}
It Display all contacts in every sections. I want to show contacts in sorted order with alphabetical index a to z
You're returning self.results.count in numberOfRowsInSection regardless of which section you are in. You have to return the number of rows for each letter. Consider using a dictionary with letters as the keys and contacts as the values.

UITableView Reordering Of Cells-Reorder/Edit Mode Not Displaying (Swift)

I have a UITableView inside a UIViewController. I am trying to make it so when the user click the BarButtonItem in the NavigationBar, that the tableview goes into editing mode, and thus the user can drag and reorder the cells.
However, what happens is that I simply press the editing button, and nothing happens.
This is what I have tried:
For the array declaration:
var tester = ["1", "2", "3"]
For the button declaration:
#IBAction func editButtonPressed(sender: AnyObject) {
self.editing = !self.editing
}
For the various tableview functions:
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return tester.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("editCell", forIndexPath: indexPath) as! EditTableViewCell
cell.nameHolder?.text = tester[indexPath.row]
// Configure the cell...
return cell
}
func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
var itemToMove = tester[fromIndexPath.row]
tester.removeAtIndex(fromIndexPath.row)
tester.insert(itemToMove, atIndex: toIndexPath.row)
}
func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the item to be re-orderable.
return true
}
What could be causing this bug?
Swift 4.1
In → func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
Add this line to configure the cell:
cell.isEditing = self.tableView(tableView, canMoveRowAt: indexPath)
Ran Hassid has the most correct answer to this in his comment.
This will solve the problem:
#IBOutlet weak var tableView: UITableView!
#IBAction func editButtonPressed(sender: AnyObject) {
tableView.setEditing(!tableView.isEditing, animated: true)
}

Conform to protocol in ViewController, in Swift

Trying to conform to UITableViewDataSource and UITableViewDelegate inside a Swift UIViewController subclass.
class GameList: UIViewController {
var aTableView:UITableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
aTableView.delegate = self
aTableView.dataSource = self
self.view.addSubview(aTableView)
//errors on both lines for not conforming
}
}
Docs say you should conform on the class line after the : but that's usually where the superclass goes. Another : doesn't work. Using a comma separated list after the superclass also doesn't work
EDIT:
Also must adopt all required methods of each protocol, which I wasn't initially doing.
You use a comma:
class GameList: UIViewController, UITableViewDelegate, UITableViewDataSource {
// ...
}
But realize that the super class must be the first item in the comma separated list.
If you do not adopt all of the required methods of the protocol there will be a compiler error. You must get all of the required methods!
As XCode6-Beta7 releases,
I noticed the protocol method of UITableViewDataSource changed a little bit and sounded the same conform to protocol error which worked fine in beta6.
These are the required methods to be implemented according to the UITableViewDataSource protocol:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // insert code}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // insert code
}
You might want to re-check the difference or re-implement the delegate method that you thought you just implement.
You must implement two require methods here:
func tableView(tableView:UITableView!, numberOfRowsInSection section:Int) -> Int {
return 10
}
func tableView(tableView:UITableView!, cellForRowAtIndexPath indexPath:NSIndexPath!) -> UITableViewCell! {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
cell.text = "Row #\(indexPath.row)"
cell.detailTextLabel.text = "Subtitle #\(indexPath.row)"
return cell
}
Also, it is important to copy all the non optional functions from the Delegate class. Cmd + Click on the UITableViewDatasource
and copy those two definitions as is.
For me in beta7, the UITableViewDatasource has
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
My implementation:
var items = ["Apple", "Pear", "Banana"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Default")
cell.textLabel?.text = items[indexPath.row]
cell.detailTextLabel?.text = "Test"
return cell
}
Usee These methods:
There is change in Data source methods-
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
protocol UITableViewDataSource : NSObjectProtocol {
****func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell****
optional func numberOfSectionsInTableView(tableView: UITableView) -> Int // Default is 1 if not implemented
optional func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? // fixed font style. use custom view (UILabel) if you want something different
optional func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String?
// Editing
// Individual rows can opt out of having the -editing property set for them. If not implemented, all rows are assumed to be editable.
optional func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool
// Moving/reordering
// Allows the reorder accessory view to optionally be shown for a particular row. By default, the reorder control will be shown only if the datasource implements -tableView:moveRowAtIndexPath:toIndexPath:
optional func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool
// Index
optional func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]! // return list of section titles to display in section index view (e.g. "ABCD...Z#")
optional func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int // tell table which section corresponds to section title/index (e.g. "B",1))
// Data manipulation - insert and delete support
// After a row has the minus or plus button invoked (based on the UITableViewCellEditingStyle for the cell), the dataSource must commit the change
// Not called for edit actions using UITableViewRowAction - the action's handler will be invoked instead
optional func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)
// Data manipulation - reorder / moving support
optional func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath)
}
Ur code will works!!
This question is already answered but just want to make things a bit more Swifty.
Instead of writing protocols in UITableViewDelegate, UITableViewDataSource you can divide them using extensions this will help in organising the code. Adding protocol conformance is described in this page
for the above question, this can be confirmed to protocol using extension:
class GameList: UIViewController {
var aTableView:UITableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
aTableView.delegate = self
aTableView.dataSource = self
self.view.addSubview(aTableView)
}
}
extension GameList: UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath)
return cell
}
}
extension GameList: UITableViewDelegate{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Row Clicked at \(indexPath.row)")
}
}

Resources