Adding label to a prototype cell - ios

I need to add a label to a prototype cell but I am getting the error "Value of type 'UITableViewCell' has no member 'movieTitleLabel'.
import UIKit
class FirstTableView: UITableViewController {
let model = MovieModel()
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSections(in 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 model.MovieArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "movieCells", for: indexPath) as! TableViewCell
cell.movieTitleLabel?.text = model.movieArray[indexPath.row]
return cell
}
I have the FirstTableView set as the delegate and datasource, in the editor.
I created a new subclass named: TableViewCell, linked the label to that class. Now I am at at loss as to how to output the movieArray to that label.

You forgot to downcast cell to your UITableViewCell subclass so you have reference just to superclass UITableVoewCell and this superclass hasn’t any movieTitleLabel.
To fix this, add as! YourTableViewCellSubclass to the end of the line where you dequeue cell
let cell = tableView.dequeueReusableCell(withIdentifier: "movieCells", for: indexPath) as! YourTableViewCellSubclass

Look out into these points:
You have created an outlet of the label named as 'movieTitleLabel' in ViewController, but this label should be in TableCell class. Make correct reference of this label.
After the first point, now to access this label, follow this code:
Code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "YourTableCellIdentifier", for: indexPath) as! YourTableCellClass
cell.movieTitleLabel.text = "Text" // Set your text here now
return cell
}

Your prototype cell should have specified an implementation class - this must be a subclass of UITableViewCell. If you've done this, downcast the result of dequeueReusableCell to this class.
You should also have connected the movieTitleLabel outlet in that class to the label in the storyboard. It looks from the above as if you've connected it to the UITableViewController instead (#IBOutlet weak var movieTitleLabel: UILabel!). You should remove this from the VC and only have it in the UITableViewCell class.

Related

embed custom view into UITableViewCell

I already have a subclass of UIView, called CustomView, which I use in stack views.
I am wanting to redo the UI and use a table view instead. So, for that I just wanted to reuse the CustomView class I already have but for some reason the table view is not showing the cell at all.
I think the issue is the way I am using CustomView in CustomCell: UITableViewCell:
class CustomCell: UITableViewCell {
#IBOutlet var customView: CustomView!
}
in the view controller holding the table view, I have in viewDidLoad:
tableView.register(UINib(nibName: "CustomCell", bundle: Bundle.main), forCellReuseIdentifier: "CustomCell")
and
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
return tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
When I run the app, I just get a blank table view.
Good day I made the same code that you, and works , could you add breakpoint in this position.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
return tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath)
}
you shouldn't have problem using custom views inside cells.
You have to use designated initializer for your custom view like init(frame:CGRect) or add it to the interface builder, like a prototype cell.

Content views are not displayed on the UITableViewCell

This is a part of my storyboard:
this is my running app:
This is my part of codes:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
if indexPath.row == 0 {
return super.tableView(tableView, cellForRowAt: indexPath)
} else {
tableView.register(SubTextFieldCell.self, forCellReuseIdentifier: "SubTextFieldCell")
let cell = tableView.dequeueReusableCell(withIdentifier: "SubTextFieldCell", for: indexPath) as! SubTextFieldCell
// cell.deleteButton.isEnabled = true
// cell.subTextfield.text = "OK"
print("indexPath.row: \(indexPath.row)")
return cell
}
...
I have already connected the button and the textfield in various places and I can guarantee that this part is not wrong, but when I click the Add button in the first row, I only get a cell without any content.
If I use code like this cell.deleteButton..., Xcode will report an error:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an
Optional value
Then I tried to use the viewWithTag method to see if show the content, but I still get the same error as before.
This is the first time I have encountered this kind of error. I have no error with similar code and methods in my other programs.
When you configure custom cells inside a storyboard file, you don't need to call register(_:forCellReuseIdentifier:) because the storyboard should have done that for you.
The reason deleteButton is nil is because by re-registering the cell class as you did, you overwrote what the storyboard registered for you. All cells created by dequeueing with that reuse identifier will have no connection to the storyboard and simply be empty.
Assuming all the #IBOutlets and reuse identifiers and things are set up (which you said you did), then simply dequeue the cell with the reuse identifier set up in storyboard.
Dequeue Cell Example:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
if indexPath.row == 0 {
return super.tableView(tableView, cellForRowAt: indexPath)
} else {
// Registering again is unnecessary, because the storyboard should have already done that.
// tableView.register(SubTextFieldCell.self, forCellReuseIdentifier: "SubTextFieldCell")
let cell = tableView.dequeueReusableCell(withIdentifier: "SubTextFieldCell") as! SubTextFieldCell
cell.deleteButton.isEnabled = true
cell.subTextfield.text = "OK"
return cell
}
} else {
...
}
}
Note:
Even in cases where you do need to register a class with a table view, you should only have to do this once. (For example, during viewDidLoad)
Even in those times, you should not call it every time you dequeue a cell. You're just making your app work harder.
Connecting views to cells in Storyboard
Set a subclass to the table view
Set a subclass to the first prototype cell
Set a reuse identifier to the prototype cell
Make sure subview (UIButton, etc.) is connected to property with #IBOutlet (subclass code shown below)
Example UITableViewController subclass:
class MyTableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyFirstCell", for: indexPath) as! MyFirstTableViewCell
// Configure cell if needed
cell.myButton.setTitle("New Button Text", for: .normal)
cell.myButton.tintColor = .green
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "MySecondCell", for: indexPath) as! MySecondTableViewCell
// Configure cell if needed
cell.myTextField.backgroundColor = .red
return cell
}
}
}
Example UITableViewCell subclass:
class MyFirstTableViewCell: UITableViewCell {
#IBOutlet weak var myButton: UIButton!
}
Result:

Why is my tableView not being populated?

I'm trying to populate a basic tableview with sample data in code. Here's my ViewController:
import UIKit
class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var postTableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postcell", for: indexPath)
cell.textLabel?.text = "title"
cell.detailTextLabel?.text = "detail"
return cell
}
}
Here is my storyboard
I'm sure that the name "postcell" is correct and that I've hooked up the tableView to the ViewController as a datasource and delegate.
When I run the code in the iOS simulator, no cells show up. This is what I see:
Here are the constraints on my stack view
stack view properties
I don't want to use UITableViewController
How do I get the table cells to appear?
If "postcell" is not a prototype cell from your storyboard, you need to register it in your viewDidLoad:
postTableView.register(UITableViewCell.self, forCellReuseIdentifier: "postcell")
If it is a XIB table view cell you would register it as follows:
postTableView.register(UINib(nibName: "NibName", bundle: nil), forCellReuseIdentifier: "postcell")
If you were to do it from storyboard, drag a prototype cell (or table view cell) onto your table view and in the reuse identifier call it "postcell" as shown here:
Make sure you have also done the following in your viewDidLoad:
postTableView.delegate = self
postTableView.dataSource = self
Of course, you'll also need:
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: "postcell", for: indexPath) as postcell // add this line
Thank you #MrSaturn for pointing out in the comments that it's a problem with the stack view. In storyboard I had to change the stack view's alignment property from center to Fill.

UITableViewCells invisible

Requirement :
I have a list of UITableviewCell loaded from a nib that I'm presenting on UITableview. The first time I open the UIViewController all cells are shown correctly and work as expected.
Issue :
If I navigate back to the parent and then open the UIViewController again the UITableviewCell are 'invisible'. I say invisible because with a breakpoint in cellForRowAt I can see that the table view does load all cells and the cells are valid.
Code :
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 13
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 40
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = (project?.sliderData.sliders[indexPath.row].view)! as UITableViewCell
print(cell.contentView.subviews.count)
if let left = cell.viewWithTag(2) as? UILabel {
left.text = "left"
}
if let middle = cell.viewWithTag(3) as? UILabel {
middle.text = "middle"
}
if let right = cell.viewWithTag(4) as? UILabel {
right.text = "right"
}
return cell
}
Screen Shot Image
Expected observation :
I was thinking that maybe the subviews of the cells get released because I don't have any bindings to them in IB. To test this I'm printing the count of subviews and writing some text to the subview labels. And everything seems to go fine, the cells are loaded and the labels are there but the cells just don't show up.
But then, if I scroll the TableView up and down a little to get some cells updated those cells do appear at the top and bottom of the view as shown in the pic.
You need to call dequeueReusableCell(withIdentifier: "cell") inside your code then will show your table cell. It will reuse cell for your all numbers of row data content.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! UITableViewCell
return cell
}
More Details : How to create uitableview with multiple sections in iOS Swift.
Did not find reason why the tableView behaves the way it does so I solved the issue by dequeueing default cells. The views provided by the slider objects are added as subviews to the dequeued cells. Now the subviews can of course be any UIViews.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "sliderCell")
if cell == nil {
cell = UITableViewCell.init(style: .default, reuseIdentifier: "sliderCell")
}
cell?.addSubview((project?.sliderData.sliders[indexPath.row].view)!)
return cell!
}

Set TextLabel's text in tableViewCell

I am coming to you for a little issue I have, that might actually not be that complicated but that i have struggled about for now about an hour...
I defined a TableViewCell in a TableViewController. This TableViewCell has three UIImage and two textLabels. I implemented the following methods :
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fruits.count
}
(which in my sense defines the number of rows)
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "friendListCell")
cellOutlet.nameTextLabel.text = fruits[indexPath.row]
return cell!
}
On this second method, the "cellOutlet" is an instance of the class that defines my cell, in which I modify one of the textLabel's text.
"fruits" is a simple array of Strings that are supposed to be displayed in every cell of my app one by one.
Compilation goes fine, but when accessing the page in question, the app crashes saying
unexpectedly found nil while unwrapping an Optional value
My question is the following :
Would you have any idea of what is done wrong in term of accessing my textLabel's text ?
Thanks in advance !
If you're using a custom TableViewCell class you have to
Set the class of the cell in Interface Builder to the custom class
Cast the cell accordingly in cellForRow... (assuming the name is MyTableViewCell)
let cell = tableView.dequeueReusableCell(withIdentifier: "friendListCell" for:indexPath) as! MyTableViewCell
Try to call
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "friendListCell")
cell.nameTextLabel.text = fruits[indexPath.row]
return cell!
}
and also check "cell" should not be nil at the time of calling cell.nameTextLabel.text = fruits[indexPath.row]
Even if your custom UITableViewCell class (e.g. FruitsCell) has some labels, the standard UITableViewCell doesn't (apart from one, which is its 'label' property). In your code, the 'cell' property is of type UITableViewCell, which has no cellOutlet or nameTextLabel property to access.
If you set up your custom cell in IB, be sure to connect all your labels from IB with the code in your Swift-File, e.g. FruitsCell.swift, that contains the FruitsCell class.
Then cast the 'cell' in your ViewControllers delegate method as e.g. FruitCell instead of UITableViewCell. Only then you can access the labels of that class that you set up in IB.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// casting to your Class
let cell = tableView.dequeueReusableCell(withIdentifier: "friendListCell") as! FruitCell
// accessing that Class' properties
cell.nameTextLabel.text = fruits[indexPath.row]
// returning cell of type FruitCell
return cell!
}

Resources