IBoutlet is nil in my custom table cell? - ios

//custom cell in one swift file
import UIKit
class CardTableViewCell: UITableViewCell {
#IBOutlet weak var elapsedTime: UILabel!
#IBOutlet weak var todo: UILabel!
#IBOutlet weak var startAndStop: UIView!
#IBOutlet weak var progress: UIView!
#IBOutlet weak var cardView: UIView!
}
//custom Table view controller in another swift file
import UIKit
class CardFeedTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CardTableViewCell.self, forCellReuseIdentifier: "cardCell")
tableView.delegate = self
tableView.dataSource = self
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CardTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cardCell", for: indexPath) as! CardTableViewCell
cell.todo.text = "study"
return cell
}
running the app triggers a error
storyboard
I don't know why all the properties in the my table cell is nil, when I run the app.

There are two variants to register, but both take a parameter called
forCellReuseIdentifier, which is a string that lets you register
different kinds of table view cells. For example, you might have a
reuse identifier "DefaultCell", another one called "Heading cell",
another one "CellWithTextField", and so on. Re-using different cells
this way helps save system resources.
If you want to use register() with a Swift class, you provide a table
view cell class as its first parameter. This is useful if your cell is
defined entirely in code. As an example, this uses the default
UITableViewCell class:
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DefaultCell")
You can then dequeue that cell like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DefaultCell")!
return cell
}
The other option is to use register() with an Interface Builder nib
file. Nibs contain the class name to use along with their design, so
this method is more common. Here's an example
tableView.register(UINib(nibName: "yourNib", bundle: nil), forCellReuseIdentifier: "CellFromNib")
But if you're using storyboards you will find it easier to create
prototype cells and give them a reuse identifier directly inside
Interface Builder.So no need to register programmatically.
Remove this line form viewDidLoad
tableView.register(CardTableViewCell.self, forCellReuseIdentifier: "cardCell).

Related

Swift crash when unwrapping UILabel in UITableView with custom cell

I have a Table Bar where i have 3 separate MVC. The first MVC is a UITableView where i can search for a location and it will display 10 day forecast. The second MVC also a UITableView stores my favourite locations. I can tap on the location and it will bring me another UITableView that displays the 10 day forecast just like the first tab bar. However i get an "Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value" I'm using a custom prototype cell just like the first tab bar view and it works great there.
The code for my first tab bar mvc looks like:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "WeatherDataCell", for: indexPath)
let weatherCell = timeSeries[indexPath.row]
if let wc = cell as? WeatherTableViewCell {
wc.timeSeries = weatherCell
}
return cell
}
The custom prototype cell looks something like:
class WeatherTableViewCell: UITableViewCell {
#IBOutlet weak var WeatherImageView: UIImageView!
#IBOutlet weak var WeatherTimeLabel: UILabel!
#IBOutlet weak var WeatherTemperatureLabel: UILabel!
#IBOutlet weak var WeatherWindLabel: UILabel!
#IBOutlet weak var WeatherPrecipitationLabel: UILabel!
var timeSeries : TimeSeries? {
didSet {
updateUI()
}
}
func updateUI() {
for parameters in timeSeries!.parameters {
if parameters.name == "t" {
let temperature = parameters.values[0]
WeatherTemperatureLabel.text? = "\(temperature) °C" // <- works for the first MVC but crashes on the second MVC even though i can print out the temperature
}
}
}
The func in the seconds MVC basically looks the same as the first one so i don't understand why its crashing, it should have data.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DetailedWeatherCell", for: indexPath) as! WeatherTableViewCell
let weatherCell = timeSeries[indexPath.row]
let wc = cell
wc.timeSeries = weatherCell
return cell
}
added additional code for clarity (my FavoriteDetailedTableViewController class):
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(WeatherTableViewCell.self, forCellReuseIdentifier: "DetailedWeatherCell")
}
I think you forgot to change identifier of prototype cell in FavoritedDetailedTableViewController. In this TableViewController change it to
and it should work.
Second you maybe forgot to set your cell class here
Also delete this line from viewDidLoad
self.tableView.register(WeatherTableViewCell.self, forCellReuseIdentifier: "DetailedWeatherCell")
2 Viewcontrollers can not reuse the same prototype cell which had been created by one of two viewcontrollers
WeatherTableViewCell can't have 2 layouts in mvc1, mvc2
=> You have to create your customer cell in xib file and register a cell for UITableViewCell reuse.

Implementing UITableView with three "columns" in MapView [Swift]

i'm trying to implement the following design with MapBox and a TableView.
I've been thinking about it and I wanted to use a UITableView for the results, but as far as I know, it's only possible to have data and detail on the left & right side. Is there an alternative to UITableView ?
If not, i'm also facing the problem that my "root"-View is a MapView (from MapBox) and that I can't use the MapViewController as UITableViewController nor as UITableViewDelegate/UITableViewDataSource. Is it possible to Embed the MapView in another View ?
If you need any more information, just let me know. And thank you in advance.
but as far as I know, it's only possible to have data and detail on the left & right side. Is there an alternative
You know wrong. You can include any interface you want in a table view cell. Just make this a custom cell and design it as desired.
Assuming that you have a UIViewController in your storyboard or xib called ViewController which has both a UITableView and an MKMapView (or whatever you are using) correctly connected to the two outlets in the code below:
import UIKit
import MapKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Now tell the system that we are going to reference our
// hand-made table cell from a xib called "MyCell"
self.tableView.register(UINib(nibName: "MyCell", bundle: nil), forCellReuseIdentifier: "MyCell")
// These next you can do here, or in IB...
self.tableView.dataSource = self
self.tableView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: - TableViewDataSource
// ANY ViewController can do this, if we register the class as conforming
// to the `UITableViewDataSource` protocol
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Get a reference to an instance of our very own UITableViewCell subclass,
// Which we registered in `viewDidLoad`
let c = self.tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
// Whatever controls/outlets we have put in our cell subclass,
// we need to populate with data now... (I just did a label)
c.cellNumber?.text = "\(indexPath.row)"
return c
}
//MARK: - TableViewDelegate
//... implement whatever funcs you need ...
//MARK: - MKMapViewDelegate
//... implement whatever funcs you need ...
}
You then need to create the following code, AND a stand-alone xib (called in this case "MyCell.xib"). The xib should contain all of the controls you want in your table cell. In my example it has only one control, the UILabel referenced as cellNumber.
To make the xib, choose "File->New File->User Interface->Empty" from the Xcode menu, then drop a UITableViewCell into the xib from the palette. Make sure you change the class of the cell from UITableViewCell to MyCell. Add whatever controls (and constraints between them) that you need. Obviously, connect all of your controls to relevant #IBOutlets in this class.
class MyCell: UITableViewCell {
// Create `#IBOutlet weak var ...` for all of the controls in your cell here
#IBOutlet weak var cellNumber: UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.configureCell()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.configureCell()
}
func configureCell() {
// Your stuff to load up the IBOutlet controls of your cell with defaults.
// You will be able to override these when the instantiated cell is passed to
// `tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell`
// in the `UITableViewDataSource`
}
}

Using a cell in another file in Swift

I would like to keep the content of a UITableView cell in a separate file as I do in Objective-c even in my TodayExtension Swift table in order to wire it to the storyboard. Yet when I try to do it, it complaints it cannot find the class of the cell; this is the function I use:
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
println(indexPath)
let cell = tableView.dequeueReusableCellWithIdentifier(
TableViewConstants.cellIdentifier,
forIndexPath: indexPath) as! TodayCell
let entry = busCollection[indexPath.row]
cell.bus=entry.bus
cell.destination=entry.destination;
return cell
}
todayCell is the class in another file it reports it cannot find:
import UIKit
class TodayCell: UITableViewCell {
#IBOutlet var bus: UILabel!
#IBOutlet var stopAddress: UILabel!
#IBOutlet var destination: UILabel!
}
Importing the file, even if not needed according the the Swift documentation, moved the error in the import statement.
Programmatically:
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(todayCell.self, forCellReuseIdentifier: "todayCell")
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("todayCell", forIndexPath: indexPath) as! todayCell
// Setup
return cell
}
This should do it.
Storyboard:
If you're using prototypes, then you just have to set the prototype class to todayCell and an identifier. This identifier is used when you're creating the cell in tableView.dequeueReusableCellWithIdentifier()
I found the problem: Xcode forgot to add the new TodayCell file to the list of compile sources when I added it to the project. Once I manually did it everything worked fine - I had a funny horror trip in a list of errors in the MKStoreManager library, but all of them went away upon returning to the last commit.

Swift Custom UITableViewCell not displaying data

I am new to Swift, and iOS development in general. I am attempting to create a custom UITableViewCell. I have created the cell in my main storyboard on top of a UITableView that is inside a UIViewController. When I loaded one of the default cells, I was able to populate it with data. However, now that I am using a custom cell, I cannot get any data to appear in the table. I have gone through all kinds of tutorials and questions posted on the internet, but I can't figure out why it is not working. Any help would be appreciated.
Here is my code for the UIViewController that the tableview resides in.
import UIKit
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tblView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//self.tblView.registerClass(UITableViewCell.self, forCellReuseIdentifier : "Cell")
self.tblView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier : "Cell")
tblView!.delegate = self
tblView!.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataMgr.data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : CustomTableViewCell = self.tblView.dequeueReusableCellWithIdentifier("Cell", forIndexPath : indexPath) as! CustomTableViewCell
var values = dataMgr.data[indexPath.row]
cell.newTotalLabel?.text = "\(values.newTotal)"
cell.winLoseValueLabel?.text = "\(values.newTotal - values.currentTotal)"
cell.dateLabel?.text = "5/17/2015"
return cell
}
}
I have stepped through the program where it is assigning values to the cell variables. The variable 'values' is being populated with data, but when stepping over the assignment lines to the cell variables, I found that they are never assigned. They all remain nil.
When you make a custom cell in the storyboard, don't register the class (or anything else). Just be sure to give the cell the same identifier in the storyboard that you pass to dequeueReusableCellWithIdentifier:forIndexPath:.

Swift custom UITableViewCell label is always nil

I've been stuck with this problem for days, so I'd be really happy if someone could help.
I'm trying to create a dynamic UITableView, for which I created a custom UITableView subclass and I've created a custom UITableViewCell subclass as well, because I need several UILabels and a UIButton in each cell.
The cell is created, but the problem is that the value of the labels is always nil, hence the cell isn't displayed properly.
This is, how the storyboard looks like, and this is what I see while running the program.
Here's my UITableViewCell subclass:
import UIKit
class QuestionTableViewCell: UITableViewCell {
#IBOutlet var student: UILabel!
#IBOutlet var labDesk: UILabel!
#IBOutlet var topic: UILabel!
#IBOutlet var answers: UILabel!
}
and my UITableView subclass:
import UIKit
class QuestionViewController: UITableViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var table: UITableView!
struct Question {
var student: String
var labDesk: String
var topic: String
var answered: String
}
override func viewDidLoad() {
super.viewDidLoad()
table.estimatedRowHeight = 50
table.dataSource = self
table.delegate = self
self.table.registerClass(QuestionTableViewCell.self, forCellReuseIdentifier: "cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as QuestionTableViewCell
cell.student.text = "random string"
cell.labDesk?.text = "25/A"
cell.topic?.text = "string"
cell.answers?.text = "3"
return cell
}
}
Try removing self.table.registerClass(QuestionTableViewCell.self, forCellReuseIdentifier: "cell")
If you're using a cell with a nib then make sure that you are registering the cell with the table view using registerNib:forCellReuseIdentifier:. If the cell just has a class then use registerClass:forCellReuseIdentifier:.
First, you don't have to register the class if it exists in Interface Builder.
Second, you should dequeueReusableCellWithIdentifier:forIndexPath instead of dequeueReusableCellWithIdentifier.
Third, UITableViewController already has a property called tableView so there is no need to make an IBOutlet to table as UITableViewController already handles this. It also conforms to the UITableViewDataSource and UITableViewDataSource so these are extraneous.
Fourth, don't set the properties for table set them for tableView.
Fifth, cell.labDesk.text = "" is sufficient, no need to make it optional.
If all your IBOutlets are hooked up, Cell Identifiers correctly set, and these revisions are made, it will work.
class QuestionTableViewCell: UITableViewCell {
#IBOutlet var student: UILabel!
#IBOutlet var labDesk: UILabel!
#IBOutlet var topic: UILabel!
#IBOutlet var answers: UILabel!
}
class QuestionViewController: UITableViewController {
struct Question {
var student: String
var labDesk: String
var topic: String
var answered: String
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 50
tableView.dataSource = self
tableView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as QuestionTableViewCell
cell.student.text = "random string"
cell.labDesk.text = "25/A"
cell.topic.text = "string"
cell.answers.text = "3"
return cell
}
}
The most important part is to register the xib containing the custom cell with the table view. Therefore add the following code in viewDidLoad() method.
let nib = UINib.init(nibName: "MyCustomCell", bundle: nil)
self.tblUsers.register(nib, forCellReuseIdentifier: "MyCustomCell")
I might be late here, but I just solved a similar problem.
Make sure you've set the Identifier in InterfaceBuilder on your UITableViewCell.
For those who are still trying to figure this out after trying all those possible solutions:
Disconnect/Reconnect the IBOutlets in your Storyboards should do the trick!
Don't forget to add:
tableView?.register(UINib(nibName: "xyz",
bundle: nil),
forCellReuseIdentifier: "abc")
If you are using a table cell with Xib. you need to register your cell with ..
register(_:forCellReuseIdentifier:)
If you haven't added constraints for the label then they will not be created though the custom cell is created.
Make sure you added some constraints.
Make sure that the selected cell is in the right "module" and if necessary, inherit:
If not, your IBOutlets will be nil.
Issue I was facing: TableViewCell has been created and all the IBOutlets are nil. So I can't set any values such as text or color etc. Below code worked for me.
Xcode version: 13.3
Step 1:
Remove datasource and delegate reference form storyboard.
Step 2:
In viewDidLoad add,
tableView.delegate = self
tableView.dataSource = self
Step 3:
In tableview UITableViewDataSource cellForRowAt function, add your cell the given way.
let cell = tableView.dequeueCell(ofType: YourCellName.self)
cell.yourCellFunction()
return cell
Note 1: dequeueCell(ofType...) is calling the below function internally. you don't need to use it directly.
func dequeueCell<T: UITableViewCell>(ofType type: T.Type) -> T {
}
Important: You don't need to provide any "Resporation ID" or "Reuse Identifier" for cell. It works with your cell name.

Resources