Static TableView gets NSRangeException - ios

I have a UITableViewController with static cells, and when I run the app and click on the button that leads to it, I get a SIGABRT signal in AppDelegate.
I tried to find unused outlets, but it didn't work.
Here is the Console Log:
The UITableViewController Code:
import UIKit
import os.log
class SettingsTableViewController: UITableViewController {
// MARK: Properties
#IBOutlet weak var noteDisplayKindSwitch: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
notedisplayKindSwitch.setOn(Settings._displaynotesAsNames, animated: false)
}
#IBAction func ChangeNoteDisplayKind(_ sender: UISwitch) {
Settings._displayNotesAsNames = sender.isOn
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
}
The UITableViewController in the Storyboard:
The Connections:
What am I doing wrong?
Thanks.

You are using static cells. There is no reason to implement numberOfSections and numberOfRowsInSection because those are specified by the static layout in the Storyboard.
Because you have implemented:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
you are telling iOS that every section has 3 rows, which is a lie. So iOS tries to access the second row of your first section and crashes with array index out of range because that section has just 1 row.
So, delete the implementations of numberOfSections and numberOfRowsInSection and you should be good to go.

Read the error message, and please do not post images of code.
Somewhere in your tableView:cellforRowAtIndexPath method, there's an empty array but you're trying to access the element at index 1.

Related

UITableViewDiffableDataSource: how to get a section index

I'm trying to adopt the new iOS 13 UITableViewDiffableDataSource and I've hit a snag; I can't work how to implement
func sectionIndexTitles(for tableView: UITableView) -> [String]?
That's a data source method, not a delegate method. So, now that the data source is the UITableViewDiffableDataSource, it needs to implement that method. But it doesn't.
I tried subclassing UITableViewDiffableDataSource and adding an implementation of sectionIndexTitles, but my implementation was never called:
class MyDataSource : UITableViewDiffableDataSource<String,String> {
func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return self.snapshot().sectionIdentifiers // not called
}
}
Has anyone solved this one? I'll file it as a bug just in case.
You need to subclass UITableViewDiffableDataSource and then overwrite
func sectionIndexTitles(for tableView: UITableView)
by yourself.
To enable the index' functionality though, you have to also overwrite
func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int)
Here is an example how I implemented it:
import UIKit
import MediaPlayer
class TableViewDiffableDataSource: UITableViewDiffableDataSource<String, MPMediaItemCollection> {
var sectionTitles = [String]()
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return sectionTitles
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sectionTitles[section]
}
override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
return sectionTitles.firstIndex(of: title) ?? 0
}
}
Credits go to Steve Breen, who led me in the right direction.
After you init self.dataSource to UITableViewDiffableDataSource (which sets itself to the tableView.dataSource) set the tableView.dataSource back to self, i.e. the UITableViewController subclass. Now in your numberOfSectionsInTableView and numberOfRowsInSection methods forward those to self.dataSource and return its info (this is the composition pattern). Now your UITableViewController just implements its section titles as normal since it is the table's data source.
I believe UITableViewDiffableDataSource should not be setting itself as the dataSource if one is already set but I guess they designed it to work in the least error prone way because with UITableViewController added to a storyboard it's set as the dataSource and delegate by default.

Add delegate and dataSource for extension view

First of all, I'm not sure the name of it is "extension view", please look at the screenshot, I mean the view with the yellow background.
I have made a custom table view in this view, and I did all the configurations, the problem is, in the end, I have to add delegate and dataSource for it.
Let's call the table cell inside of the view "OptionTableView".
I wrote these lines the viewdidload of the view controller (the controller that is inside the iPhone frame in the screenshot),
override func viewDidLoad() {
super.viewDidLoad()
OptionTableView.delegate = self
OptionTableView.dataSource = self
}
but it crashes the app with this error:
Thread 1: signal SIGABRT
Because it's UiView, I can't make a new file with a type of UIControlView for it.
Could you help me? How I can add delegate and dataSource for this extension UIView or whatever is called, that let me to use tableview inside it?
Thank you so much for your help
I think you not add protocol of tableview. I write a code for this:-
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var table_view: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
table_view.dataSource = self
table_view.delegate = self
}
}

Prepare number of sections and row before UITableViewController gets called

I have a subclass of UITableViewController where I have 2 properties that will defines the number of sections and number of rows in section
It seems the the delegate methods numberOfSectionsInTableView(tableView: UITableView) -> Int get called before viewDidLoad() which is where I am initialising the 2 properties at currently. Therefore the 2 properties does not have any value when the delegate methods get called.
Where should I initialise these 2 value such that it will be ready for the delegate method.
It shouldn't be calling that delegate func before viewDidLoad.
I just tested the following code:
override func viewDidLoad() {
super.viewDidLoad()
print("viewDidLoad")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("whatt????")
}
When I run my app, this prints:
viewDidLoad
whatt???
whatt???
whatt???
I would test that your variables are properly initialized. If they are, you should have no problem using them to define how many rows/sections you have.

TableViewController Detect Row Tap with Static Cells

I'm using a TableViewController that has a table with 2 sections of static cells. This is embedded in a view controller. I cannot get didSelectRowAtIndexPath to run when I tap the cells. I've already check all of the usual suspects from this question as well as this one. When I try with a table view inside a viewcontroller with a dynamic table, I am able to get it to work just fine. Is there an issue with using a TableViewController with static cells that would not allow for using didSelectRowAtIndexPath?
Here is what I have in the custom class for the TableViewController:
import UIKit
class OptionTableViewController: UITableViewController {
#IBOutlet var optionsTable: UITableView!
let numberOfRows = [7,2]
let cellIdentifier = "OptionCells"
override func viewDidLoad() {
super.viewDidLoad()
self.optionsTable.delegate = self
self.optionsTable.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
var rows = 0
if(section < numberOfRows.count){
rows = numberOfRows[section]
}
return rows
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
print("You selected cell #\(indexPath.row)!")
}
}
Update:
I tried replacing the tableviewcontroller and the viewcontroller it was embedded in but I am still not able to get didSelectRowAtIndexPath to run.
Update 2:
Does anyone know if this is possible in Swift 3? I found a working example using Swift 2.2 with a tableviewcontroller and static cells here. Maybe there is a bug doing this with Swift 3?
Wow, so it turns out that didSelectRowAtIndexPath is no longer correct in Swift 3. The correct usage is now didSelectRowAt. I didn't see this mentioned anywhere except this question which I stumbled upon.
This:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.row)!")
}
Not This:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
print("You selected cell #\(indexPath.row)!")
}
It's possible you have the wrong table view hooked up. Normally, a UITableViewController has it's tableView in the view property and you don't need to set up the data source and delegate programatically.

How to add items to UITableView using Swift?

i have been busting my brain trying to figure out how this works, but i can't seem to get it. i have tried using other tutorials, but with the many beta releases, everything keeps changing. i am fairly new to IOS development, so i'm kind of struggling.
in storyboard i have UITableView, which contains a cell with the identifier "myCell".
here's what i have so far. when i run the IOS simulator, nothing is presented on the table view.
any suggestions on how to fix this?
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = "Cell #: \(indexPath.row)" // display the row number
return cell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10; // testing out with 10 cells
}
}
Add the function
optional func numberOfSectionsInTableView(tableView: UITableView) -> Int
and return the number of sections you want.
You should make sure in the storyboard your UITableViewController has the class ViewController like so:
and that ViewController is both the delegate and datasource of the UITableViewController like so (Referencing Outlets):
You should also check that your UITableViewController is set to initialViewController if you don't see any lines at all (check the one at the bottom).

Resources