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.
Related
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.
//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).
I have a custom cell class called CurrentFilesCell with the setting code below
class CurrentFileCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var statusImage: UIImageView!
var currentContent: AircraftContent! {
didSet{
setStyles(Constants.appStyleSetting)
nameLabel.text = currentContent.contentName
dateLabel.text = currentContent.contentStatus
}
}
Within my CurrentFilesViewController I simply set it within cellForRowAtIndexPath
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CurrentFileCell", forIndexPath: indexPath) as? CurrentFileCell
cell?.currentContent = content
return cell!
}
I believe I also have everything linked correctly, as I have done something similar to this in other classes, both with cells and vc's.
My problem is that It does not load anything when run, there is no default text and no updated text after it should have been set. Here is an image showing the linkage
http://imgur.com/qlK4d5O
I'm really not sure what is going on and why this isn't working. I have tried deleting it and recreating but I must be missing something.
EDIT
Here is a picture of the debugger showing that the cell's currentContent is not empty. This is taken right before the return cell! is executed.
http://imgur.com/O250qXq
Did you register this cell in table view? If not than dqueRqusableCellWithIdentifier will return nil value...
You can register it using UITableView function "registerNib: forCellReuseIdentifier:"
In the storyboard, you must define subclass of the prototype table cell.
And then, you must define identifier of the prototype table cell as "CurrentFileCell".
Then you will show the content of the table when the app will be run.
My program keeps crashing in the cellForRowAtIndexPath method when I am trying to create a custom table cell. I have put a breakpoint on each line in the code, and the code fails after I try creating the cell variable with the error: unexpectedly found nil while unwrapping optional value. I have used custom table cells successfully many times before and have not run into this issue. It seems simple but I can't figure out what is wrong. Perhaps something in xcode changed that I'm unaware of? Any help is appreciated. Thanks!... Also, I did in fact register my custom cell in viewDidLoad. I'll include that code as well.
var nib = UINib(nibName: "FeedTableViewCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "feedCell")
Probem Code Below:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:FeedTableViewCell = tableView.dequeueReusableCellWithIdentifier("feedCell", forIndexPath: indexPath) as! FeedTableViewCell
cell.descriptionLabel.text = "Testing the description label of my cell."
return cell
}
Update
The one difference between this project and others that have worked is that Xcode is now prompting me to put a bang (!) after as, whereas before I never used one. If I don't add (!) it gives me the error message "AnyObject is not convertible to FeedTableViewCell"
as! FeedTableViewCell -instead of- as FeedTableViewCell
FeedTableViewCell Class
import UIKit
class FeedTableViewCell: UITableViewCell {
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
priceLabel.font = UIFont(name: "AvenirNext-Bold", size: 30.0)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
After spending way too much time trying to get it to work. I nuked my custom table cell, created a brand new one, set it up the exact same way, and everything is working fine now. Still have no idea what happened, but I guess the lesson from this is that sometimes you just have to nuke it and start over.
you should used like this
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("feedCell", forIndexPath: indexPath) as FeedTableViewCell
cell.descriptionLabel.text = "Testing the description label of my cell."
return cell
}
for more help used this link http://shrikar.com/blog/2015/01/17/uitableview-and-uitableviewcell-customization-in-swift/
You should use
var cell:FeedTableViewCell = tableView.dequeueReusableCellWithIdentifier("feedCell",) as! FeedTableViewCell
NSIndexPath may make this issue.
HTH, Enjoy Coding !!
I've a table view that has a custom table view cell in it. My problem is that when I try and assign a value to a variable in the custom UITableViewCell I get the stated error. Now, I think its because the said variable is not initialised, but it got me completely stumped.
This is the custom table cell:
import Foundation
import UIKit
class LocationGeographyTableViewCell: UITableViewCell
{
//#IBOutlet var Map : MKMapView;
#IBOutlet var AddressLine1 : UILabel;
#IBOutlet var AddressLine2 : UILabel;
#IBOutlet var County : UILabel;
#IBOutlet var Postcode : UILabel;
#IBOutlet var Telephone : UILabel;
var location = VisitedLocation();
func Build(location:VisitedLocation) -> Void
{
self.location = location;
AddressLine1.text = "test";
}
}
My cell for row at index path is:
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
var addressCell = tableView.dequeueReusableCellWithIdentifier("ContactDetail") as? LocationGeographyTableViewCell;
if !addressCell
{
addressCell = LocationGeographyTableViewCell(style: UITableViewCellStyle.Value1, reuseIdentifier: "ContactDetail");
}
addressCell!.Build(Location);
return addressCell;
}
As I say I'm completely baffled, the Build function calls the correct function in the UITableViewCell.
Any help will be gratefully appreciated.
Ta
I just made a simple project with your code, and I have a nil "AddressLine1" label, which causes the same error you have. I assume we have the same problem.
I solved it by adding the identifier "ContactDetail" to the prototype cell in my storyboard.
I also suggest that you change your code a little :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// This newer API ensures that you always get a cell, so no need for optionals.
// Also note the "let" that is preferred since you don't plan on changing addressCell
let addressCell = tableView.dequeueReusableCellWithIdentifier("ContactDetail", forIndexPath: indexPath) as LocationGeographyTableViewCell;
//addressCell.Build(Location); // the cell is a view, views should not know about model objects
addressCell.AddressLine1 = Location.addressLine1
// ... same for all labels, or do all that in a "configureCell" function
return addressCell;
}
I finally solved it. Instead of using the storyboard to define the UITableViewCell (as I'd done in the parent view controller) I created a Xib with the content and wired that up to the cell's class, referenced it in the TableViewController and allocated it in the cell created method.
viewDidLoad()
{
var nib = UINib(nibName: "LocationTableViewCell", bundle: nil)
tableView.registerNib(nib, forCellReuseIdentifier: "locationCell")
}
var cell:LocationGeographyTableViewCell = self.tableView.dequeueReusableCellWithIdentifier("locationCell") as LocationGeographyTableViewCell
cell.AddressLine1.text = "teetetette";
return cell;