first of all i'm saying straight forward I know this is "duplicate" and and this is my 2nd time asking the same question - the problem is that my first one has been closed without me understanding the problem so please if someone wants to close this question again first let me understand what am I doing wrong. The solution I got last time was not relevant so if I could get addressed specifically that would be great!
I am trying to create a custom cell on tableview from an array. when I append any filed on my custom cell I get unexpected nil on all of the fileds and I have no idea why
this is my custom cell:
class CustomMovieCell: UITableViewCell {
#IBOutlet weak var title: UILabel!
#IBOutlet weak var rating: UILabel!
#IBOutlet weak var releaseYear: UILabel!
#IBOutlet weak var genre: UILabel!
var imageBackground: String!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
and this is my UITableView cellForRowAtIndexPath method:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell", for: indexPath) as! CustomMovieCell
let movieFetched = Movie(title: moviesArray[indexPath.row].title, image: moviesArray[indexPath.row].image, rating: moviesArray[indexPath.row].rating, releaseYear: moviesArray[indexPath.row].releaseYear, genre: moviesArray[indexPath.row].genre)
print(movieFetched)
cell.title.text? = movieFetched.title
cell.rating.text? = String(movieFetched.rating)
cell.releaseYear.text? = String(movieFetched.releaseYear)
cell.genre.text? = String(movieFetched.genre[0])
return cell
}
what am I missing? when appending ANY of the files I get unexpectedly found nil while unwrapping optional value - I did not know UIlabel as IBOutlet are optional? even-though they are not optional in my custom cell class.
when debugging I can see that all values of the cell - title, image, rating, releaseYear and genre are nil when trying to assign them a value - so I really have no idea what to do at this point. I have deleted and re-created the cell from scratch and it did not make any differents.
As I already stated - I know this is "duplicate". please though - do not close it before you help me because I did not get any answer the last time, I got directed to a wall-of-text page that did not help me understand my issue. The other "duplicate" pages are like a general "what are optional values" kind of question and do not help me with this specific issue.
edit:
I have uploaded this project to github if it helps anyone help me to figure out this issue
https://github.com/alonsd/MoviesApi
You've connected the custom cell class with 2 cells. One is in xib and another one is in this UIViewController. This UIViewController's prototype cell doesn't have these labels. So it will be nil and it will crash
Delete the prototype cell from MoviesViewController in storyboard. And add this in MoviesViewController viewDidLoad
tableView.register(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "MovieCell")
Change tableView cellForRowAt method as follows
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell") as! TableViewCell
cell.title.text = moviesArray[indexPath.row].title
cell.rating.text = String(moviesArray[indexPath.row].rating)
cell.releaseYear.text = String(moviesArray[indexPath.row].releaseYear)
cell.genre.text = String(moviesArray[indexPath.row].genre[0])
return cell
}
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.
I am writing an iOS app in Swift that puts data from an API into a TableView. The goal is that the user can scroll down a continuous list of blog posts. What is happening is that data is filling the first screen's amount of cells fine, but when the user scrolls down, the app crashes as one of the cell properties, cellImageView becomes nil and is unwrapped (as force unwrap is specified in the cell class's code):
class BlogPostEntryCell: UITableViewCell {
//MARK: Properites
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var bodyTextView: UITextView!
#IBOutlet weak var initialsImageView: UIImageView!
}
Here is the code that causes the crash:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "NewCell", for: indexPath) as! NewCell
apiCaller.getAPIDataThroughAsyncCall(id: nextCell, entry: { cellContent in
DispatchQueue.main.async(execute: {
cell.cellLabel.text = cellContent.labelText
cell.cellTextView.text = cellContent.textViewText
// App crashes at the below line
cell.initialsImageView = self.createPicture(initials: cellContent.pictureText)
})
})
nextCell += 1
return cell
}
The interesting thing is that if do this:
cell.cellLabel?.text = cellContent.labelText
cell.cellTextView?.text = cellContent.textViewText
// App does NOT crash at the below line
cell.initialsImageView? = self.createPicture(initials: cellContent.pictureText)
, the app doesn't crash but the data just repeats over and over again as the user scrolls.
I've tried the solution to a similar problem here: Why does data returned from coredata become nil after tableview scroll in swift?, but that did not work. However, I do believe this has to do with the asynchronous API calls.
I am thinking that possible solutions may include population an array of API data before generating the cells, but I would like some insight on the source of this problem before a rethink the architecture of the code.
You need to make an API call in your viewDidLoad to know how many element are there and record their ID in an array. Then in your cellForRow function, you can get the id in this way
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "NewCell", for: indexPath) as! NewCell
apiCaller.getAPIDataThroughAsyncCall(id: array[indexPath.row], entry: { cellContent in
DispatchQueue.main.async(execute: {
...
})
})
return cell
}
The reason your nextCell wont work is that, this cellForRow function is called every time when your table view is trying to display a cell that is not currently on your screen. Say you know you have 10 element and your screen can only display 5 of them. When you scroll to bottom, your nextCell will become 10 and everything works fine as now. But now when you scroll up, the table view have to prepare the previous 5 again. So now your nextCell becomes 15, which you don't have corresponding element in your API call.
It is bad practice to call any API in cellForRowAt indexPath: IndexPath, it produces crashes as you see, have a look at MVVM. It is like wining a war without having to go to battle and I refer to this instance where you call API in cellForRowAt indexPath: IndexPath and the outlets are not initialised.
I'm new to Swift and iOS and have a situation where I would like to take an array of URL strings and populate a ImageView within a UITableViewCell, which I have made an appropriate class for, called MyTableViewCell.
It's crashing and I am getting the error:
"fatal error: unexpectedly found nil while unwrapping an Optional value"
Which I can see is happening in the viewDidLoad() when the line imageTableView.datasource = self runs.
I am setting the data and delegate in the view as so:
override func viewDidLoad() {
super.viewDidLoad()
imagesTableView.dataSource = self
imagesTableView.delegate = self
}
Below, imageUrls is an array of Strings.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: MyTableViewCell = tableView.dequeueReusableCell(withIdentifier: "myTableViewCell", for: indexPath) as! MyTableViewCell
cell.imageView.sd_setImage(with: URL(string: imageUrls[indexPath.row]))
return cell
}
I have an outlet to the cell like so in the class:
#IBOutlet var imagesTableView: UITableView!
My question is, what is the proper way to do this with swift 3 and SDWebImage, and why/where is the nil value from the imagesTableView occurring?
It may be worth noting that I have also tried hard-coding some string URL values into the imageUrls to ensure that that was not the problem (I get the same error with hardcoded values).
It turns out that although I had an outlet connected, it somehow lost the reference - I deleted the whole tableview and subviews and recreated and connected them, and the error was gone. Something funky must have happened when I drag and dropped for the outlet previously.
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 !!