Swift iOS custom cell properties can't be changed (unwrap empty optional) - ios

I have gone through all the questions regarding this matter that seems to be popular. Anyhow, I have created a simple app with a table view that uses custom cells.
I use the storyBoard, and defined the cells with the same name the class I created, Xcode even auto-completed me.
Though when I initialise a new cell, I can't change the properties of the labels and image contained in the cell. I receive an error saying I accessed a nil, and I kinda get it. Though I couldn't seem to find a way around it. Can someone help?
import UIKit
class ExtenderCell: UITableViewCell {
#IBOutlet var main_image: UIImageView!
#IBOutlet var name_label: UILabel!
#IBOutlet var desc_label: UILabel!
init(to_put_image: UIImage, name: String, desc:String){
super.init(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "cell")
name_label.text = name
desc_label.text = desc
main_image.image = to_put_image
}
}

You are using storyBoard for cell creation with outlets.Your outlets are not accessible to you till awakeForNib() using storyBoard as it is not unarchived till awakeFromNib. Your outlets or properties are nil in init so you are getting this exception as you are trying to unwrap nil outlet property in init method.
As your outlet properties are not accessible in init method and they are nil in init.So you need to set your outlets in awakeForNib().Or you can set the properties in cellForRowAtIndexPath.So best approach is to make your init method as instance method if you want to use storyBoard.
import UIKit
class ExtenderCell: UITableViewCell {
#IBOutlet var main_image: UIImageView!
#IBOutlet var name_label: UILabel!
#IBOutlet var desc_label: UILabel!
func setContents(to_put_image: UIImage, name: String, desc:String){
name_label.text = name
desc_label.text = desc
main_image.image = to_put_image
}
}
set the contents of cell in cellForRowAtIndexPath
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//Check your identifier in storyBoard is "cell"
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as ExtendedCell
cell.setContents(yourImage, name: yourName, desc: yourDescription)
return cell
}

Related

implicitly unwrapping an Optional value on custom cell of table view

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
}

Swift Custom TableViewCell wont show labels

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.

How can I call viewDidLoad in a UITableViewCell?

My code:
import Foundation
import Firebase
class CellOneViewController: UITableViewCell {
#IBOutlet weak var new1: UILabel!
let ref = Firebase(url: "https://burning-heat-8250.firebaseio.com/slide2")
func viewdidload() {
ref.observeEventType (.Value, withBlock: { snapshot in
self.new1.text = snapshot.value as? String
})
}
}
I've read around that you can't call viewDidLoad in a UITableViewCell, only in a UITableViewController. All the answers are in Objective-C, but I'm writing the app in Swift. I don't receive any critical errors but when running the app nothing appears in the cell where the label is. I'm fairly new to using Xcode, as I am just going around following guides so if I'm saying something incorrect let me know.
I think, you need method func layoutSubviews().
Only ViewController gets func viewDidLoad() called, after view is loaded.
If you need to initialize something or update views, you need to do in layoutSubviews(). As soon, your view or UITableViewCell gets loaded, layoutSubviews() get called.
Replace viewDidLoad with layoutSubviews()
class CellOneViewController: UITableViewCell {
#IBOutlet weak var new1: UILabel!
let ref = Firebase(url: "https://burning-heat-8250.firebaseio.com/slide2")
override func layoutSubviews() {
super.layoutSubviews()
ref.observeEventType (.Value, withBlock: { snapshot in
self.new1.text = snapshot.value as? String
})
}
}
The reason you can't do this is that a UITableViewCell isn't a subclass of UIViewController.
The cellForRowAtIndexPath method in the UITableViewDataSource is where you should set up your cells. You probably only want to do something like this in your custom UITableViewCell:
class CellOne: UITableViewCell {
#IBOutlet weak var new1: UILabel!
}
Then in your TableViewController's cellForRowAtIndexPath method (provided you have imported firebase) you should dequeue a reusable cell, cast it as a CellOne (as! cellOne) and then you can set the new1.text value. I don't know what your reuse identifier is, but it would look something like this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Your-Reuse-Identifier", forIndexPath: indexPath) as! CellOne
cell.new1.text = "Your Value"
return cell
}

IBAction on UISwitch in custom UITableViewCell causes error

I have a UITableViewController and a custom TableViewCell and within that UITableViewCell there is a UISwitch. This switch is wired to an IBAction, but as soon as i tap the switch, i get an error:
unrecognised selector sent to instance 0x13ce30a50
SelectFriendsViewController.swift
class SelectFriendsViewController: UITableViewController, SelectorDelegate {
func selectUser(string: String) {
selectedUser = string;
}
.... lots of code removed for simplification.
override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:SelectorTableViewCell = tableView!.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as SelectorTableViewCell;
cell.delegate = self;
}
}
protocol SelectorDelegate {
func selectUser(string: String)
}
class SelectorTableViewCell: UITableViewCell {
#IBOutlet var swUser: UISwitch! = UISwitch();
#IBOutlet var lblUserName: UILabel! = UILabel();
var delegate: SelectorDelegate!
#IBAction func SwitchUser(sender: UISwitch) {
//delegate.selectUser("test");
//even with just this println i get the error
println("test");
}
}
You have some strange stuff in this code:
your cellForRowAtIndexPath should return a cell (you probably have done this, and just didn't copy it across to your stackoverflow question)
You're generating your UISwitch either from storyboard or xib as you say 'the switch on the storyboard is highlighted' - however you're also instantiating these in code!
eg.
#IBOutlet var swUser: UISwitch! = UISwitch();
But I believe your problem in the end is related to your IBAction 'SwitchUser'. You either renamed this method at some point or created an IBAction earlier and then deleted it. To check the current status of your IBActions, click on your cell in the storyboard or xib and open the Connections Inspector. I bet you'll find your problem there.
Try changing the function name to switchUser instead of SwitchUser
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-XID_243

This class is not key value coding-compliant for the key...why?

I've linked output from the IB to the code, as shown below.
class DiaryTableViewCell: UITableViewCell {
#IBOutlet weak var TitleLabel: UILabel!
#IBOutlet weak var SubTitleLabel: UILabel!
#IBOutlet weak var leftImageView: UIImageView!
#IBOutlet weak var rightImageView: UIImageView!
}
Here, I'm registering the class:
override func viewDidLoad() {
self.title = "My Diary"
cellNib = UINib(nibName: "TableViewCells", bundle: nil)
tableView.registerClass(DiaryTableViewCell.classForCoder(), forCellReuseIdentifier: kCellIdentifier)
}
But I keep getting the following runtime error:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '...setValue:forUndefinedKey:]: this class is not key value
coding-compliant for the key SubTitleLabel.'
From within the following code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as DiaryTableViewCell?
if (cell == nil) {
tableView.registerClass(DiaryTableViewCell.classForCoder(), forCellReuseIdentifier: kCellIdentifier)
cell = cellNib?.instantiateWithOwner(self, options: nil)[0] as? DiaryTableViewCell
cell?.selectionStyle = .None
}
if (cell != nil) {
println("\(x++)) Inside cell")
cell!.TitleLabel.text = "Hello"
cell!.SubTitleLabel.text = "World"
}
return cell!
}
Specifically, it's happening here:
cell = cellNib?.instantiateWithOwner(self, options: nil)[0] as? DiaryTableViewCell
Question: How am I violating the key value coding-compliant for a UILabel?
This hasn't happened before... UILabel is KVO compliant.
I linked to the WRONG Source!
Here's the result:
You should not be calling instantiateWithOwner yourself inside tableView:cellForRowAtIndexPath.
Register the nib in viewDidLoad and then dequeueReusableCellWithIdentifier will do all the work for you.
The reason for your particular error is that you are calling instantiateWithOwner passing self as the owner and so the nib is trying to wire the outlets up to your UITableViewDataSource implementation class rather than a DiaryTableViewCell.
Show the references of your ViewController rigth-clicking in it on the Document Outline. Probably you will see a warning in one of the references. Delete it and link it again if still need it.
sometimes its like when you create button in your xib, you create one button and copy paste other buttons from one buttons, in that case this error occurs, and yes removed connections from xib could also be an reason.
I have created a TableViewCell same like your & have the same problem. I have research solving the problem but nothing. Then I delete Label in TableViewCell and recreate again, connect it to TableViewCell through File Owner,v..v And the result is right. No error. You should recreate them again.

Resources