ERROR: Method does not override any method from its superclass - ios

I'm creating a table view ui programmatically and the code i followed has no problems but mine kept telling me i have the error above? Please help
The error shows that it is at this line: override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
This is a fragment of my code:-
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath as IndexPath)
}
class MyCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
}
}

Im not sure but seem you have tableView in UIViewController? If like this, we don't need override before func cellForRowAtIndexPath . Just remove override text.

cellForRowAtIndexPath is Swift 2 code. Please look for tutorials providing contemporary code.
The syntax of Swift 3+ is
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
The override keyword is only required if the class is a subclass of UITableViewController

If you use UIViewController, just add UITableViewDataSource and UITableViewDelegate methods as like below example and don't include override keyword:
class MyViewController: UIViewController , UITableViewDataSource, UITableViewDelegate{
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}
//Other UITableViewDataSource and UITableViewDelegate methods goes here
}
If you use UITableViewController, you can override the UITableViewDataSource and UITableViewDelegate methods as like below example:
class MyTableViewController: UITableViewController{
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
}
//override other UITableViewDataSource, UITableViewDelegate methods here
}
Hope it helps!

Related

I can't dequeueReusableCell when the Cell is in its own class

I'm trying to move my "cell" code from the "func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)" function to its own class. I have registered the forCellReuseIdentifier and class with the ViewController (I think). And I have set the reuseIdentifier for the prototype cell to "MealSelector". However, when I run the code, all of the cells are blank. Why is the data not populating the tables?
Here is the view controller:
import UIKit
class MealSelectorController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var MealTable: UITableView!
#IBOutlet weak var ConfirmOrderButton: UIButton!
var recipes: [[String?]] = []
override func viewDidLoad() {
super.viewDidLoad()
for _ in 0 ..< 3 {
let recipe: Recipe = APICaller.getNewRecipe()
self.recipes.append([recipe.title, recipe.description])
}
MealTable.dataSource = self
MealTable.delegate = self
MealTable.register(MealSelectorCell.self, forCellReuseIdentifier: "MealSelector")
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.recipes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MealSelector")
return cell!
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 241
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
Here is the cell:
import UIKit
class MealSelectorCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
In a comment, you say:
It is not using my prototype cell at all to build the TableView
If that means a prototype cell in a storyboard, then delete this line:
MealTable.register(MealSelectorCell.self, forCellReuseIdentifier: "MealSelector")
That line means: Do not use the storyboard prototype. So you will need to delete it.
You will also need to set the class of the prototype cell in the storyboard.
However, I would then expect your app to crash because your init(coder:) implementation says to crash.
fatalError("init(coder:) has not been implemented")
You’ll probably want to fix that too...

Why does UITableView cache cells when reloading data?

If you were to call tableView.reloadData() on a table with custom UITableViewCell, then it will cache those cells when you reload data. (It is discussed here: https://github.com/nicklockwood/FXForms/issues/92)
If you continue reloading data, after a while, there could be 30/40 cells that are cached and retained. My question is: why is that?
In particular:
1) What possible usage could there be to retain cells that have since been lost after reloading the table?
2) What could be done to prevent/reduce the memory cache storing the cells?
3) Most importantly, why does this happen? Why would cells be retained when reloadData() is called?
Example
To give you a basic example in code, click on one of the cells, then, when you see the objects in memory, there are more retained cells:
ViewController.Swift
import UIKit
class ViewController: UIViewController {
let tableViewController = QuizTableViewController(style: .grouped)
override func viewDidLoad() {
super.viewDidLoad()
self.setupTableViewController()
}
private func setupTableViewController() {
self.view.addSubview(tableViewController.view)
let topAnchor = self.tableViewController.view.topAnchor.constraint(equalTo: self.view.topAnchor)
let leadingAnchor = self.tableViewController.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor)
let trailingAnchor = self.tableViewController.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
let bottomAnchor = self.tableViewController.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
NSLayoutConstraint.activate([topAnchor, leadingAnchor, trailingAnchor, bottomAnchor])
}
}
QuizTableViewController.Swift
import UIKit
class QuizTableViewController: UITableViewController {
override init(style: UITableViewStyle) {
super.init(style: style)
self.view.translatesAutoresizingMaskIntoConstraints = false
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = QuizCell(subText: "HELLO WORLD")
cell.textLabel?.text = "THIS IS WHAT IS DISPLAYED"
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.reloadData()
}
}
QuizCell.Swift
import UIKit
class QuizCell: UITableViewCell {
weak var subText: UILabel?
init(subText: String) {
self.subText = UILabel()
self.subText?.text = subText
super.init(style: .default, reuseIdentifier: "QuizCell")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
print("This is called after the cache is full.")
}
}
The problem is that you are not using the proper approach to creating table cells. You are explicitly creating a new instance of QuizCell in the cellForRowAt. What you should be doing is dequeueing a reusable cell using dequeueReusableCell. Then your issue goes away because the table will only keep the minimum number of cells needed.
Please find any one of the countless tutorials on using table views for proper examples.
Like #rmaddy mentioned, the problem is how you are dequeuing the cell in cellForRowAt function. Instead, change it to something similar to:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "QuizCell", for: indexPath) as! QuizCell
cell.textLabel?.text = "THIS IS WHAT IS DISPLAYED"
return cell
}

How to use UITableViewCell's accessoryButton as anchor for a Popover

I tried to use the accessoryButton of the UITableViewCell as the anchor of a Popover, but couldn't connect it using the storyboard. Programmatically I tried using the accessoryButtonTappedForRowWith function, this didn't work either. How can I connect it?
If your class is subclass of UITableViewController then use:
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
print(indexPath.row)
}
Check example code:
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "\(indexPath.row)"
cell.accessoryType = UITableViewCellAccessoryType.detailButton
return cell
}
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
print(indexPath.row)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
}
And if it's a subclass of UIViewController then you don't need override before that method so it will be:
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
print(indexPath.row)
}
And don't forget to connect UITableViewDataSource and UITableViewDelegate of your table view with your ViewController in this case.

didSelectRowAt not called in custom UITableView

After some refactoring I decided to create a custom tableview that looks a bit like:
class BaseTable: UITableView, UITableViewDelegate, UITableViewDataSource {
var rowsInSection: Int { return 0}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.delegate = self
self.dataSource = self
self.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rowsInSection
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "headerCell")!
return cell
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 40
}
And then I subclass it like this:
class CustomTable: BaseTable{
override var rowsInSection: Int {return payArray.count }
}
This works fine, however I've noticed none of the subclassed didSelectRowAt are being called??? Can anyone help?
Well, you should follow this things:
You should split up logic from initWithCoder: to external method such as and call it in initWithFrame:, because different approaches called different init methods. Such as
func setUpTableView() {
self.delegate = self
self.dataSource = self
self.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
For clarity in your code, you should explicitly call super method from child class methods
Otherwise, I strongly recommend you not to use this approach, better use standard UITableView in controller, and different classes, that implements protocols alongside with custom UITableViewCell's
This is bad design. The reason there are delegate and data source protocols for UITableViews is because view objects should be reusable. You're making your BaseTable class to function as a controller as well as a view.
To answer your question, are you sure it's not being called? You only have deselectRow(at:animated:) calling from tableView(didSelectRowAt:)

creating a custom TableViewCell in swift

I created a custom class for a cell in my program. When I try to use it in another class to create a cell I keep getting the error Cannot invoke 'init' with an argument list of type '(style: UITableViewCellStyle, reuseIdentifier: StringLiteralConvertible)'. Can anybody point me in the right direction here? I would really appreciate any help. I tried changing the class to inherit form UITableViewController so I can use this var cell: bookCell = self.tableView.dequeueReusableCellWithIdentifier("cell1") as bookCell but it crashes the program if I try to make the class inherit from tableviewcontroller.
import UIKit
class bookCell: UITableViewCell {
#IBOutlet var bookImage: UIImageView!
#IBOutlet var bookDescription: UILabel!
#IBOutlet var bookPosterUsername: UILabel!
}
import UIKit
class SubjectBooksViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var navigationBarTitle: UINavigationBar!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationBarTitle.topItem?.title = "\(selectedCourse)"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : bookCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "subjectCell")
//var cell: bookCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "subjectCell")
//var cell: bookCell = self.tableView.dequeueReusableCellWithIdentifier("cell1") as bookCell
return cell
}
}
Update code:
import UIKit
class SubjectBooksViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var navigationBarTitle: UINavigationBar!
#IBOutlet var myTableView: UITableView! //Outlet for your table View
override func viewDidLoad() {
super.viewDidLoad()
self.myTableView.dataSource = self //If you have not done in IB
self.myTableView.registerNib(yourCellNib, forCellReuseIdentifier: "subjectCell")
self.navigationBarTitle.topItem?.title = "\(selectedCourse)"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell : bookCell = tableView.dequeueReusableCellWithIdentifier("subjectCell", forIndexPath: indexPath)
return cell
}
}
In viewDidLoad() in line :
self.myTableView.registerNib(yourCellNib, forCellReuseIdentifier: "subjectCell")
replace yourCellNib with loaded nib file for your custom cell.
Registering your nib file is required if you plan to reuse cell in your table view. It is always a good idea to reuse cells.
You need to override this function and get your custom cell in this manner:
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCellWithIdentifier(
"subjectCell",
forIndexPath: indexPath) as bookCell
Your class name really should be BookCell though, with an uppercase "B". Just to keep with existing standards

Resources