I registered a custom cell call MyTableViewCell in tableview, and return a cell in datasource using dequeueReusableCellWithIdentifier method.
Now, my problem are
1: my custom cell initializer(initWithIdentifier: andModel:) can't get called.
2: when I get a reused cell, how can I update cell content with its according model?
You need to create one method in your custom cell to show data for it. Here is example..
class AddNotesTableViewCell: UITableViewCell {
//MARK: - Outlets
//MARK: - Variables
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style:style , reuseIdentifier: reuseIdentifier)
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
//MARK: - Life cycle
func setupCell(dic:NSMutableDictionary){
// Show your data in UILabel, UITextfield...
}
}
You can call setupCell method from your cellForItemAtIndexPath method. You just need to pass your current dictionary and cell will use to show data.
Related
There are many, many questions on this site and others addressing the issue of getting a Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value from trying to set an interface element in a custom table view cell.
How can I prevent the interface elements from being nil when it's time to set them?
I've done my homework and checked out the answers to these related questions.
I've made sure I don't register the class in the viewDidLoad, as I'm using a UITableViewController.
The UITableViewController is referenced properly in the Main.storyboard file.
The cells in the UITableViewController are given the proper reuseIdentifier and class.
My dequeueReusableCell call to the tableView has the proper identifier, matching the one in the storyboard.
I've broken the nib's outlets and reconnected them.
I'm setting up a UITableViewController, "FindTableViewController."
class FindTableViewController: UITableViewController {
var services = Fetch().getServices()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
/*Sections & rows defined here*/
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Monk", for:indexPath) as! Monk
let service = services[indexPath.row]
cell.set(service)
return cell
}
}
In another file, I define the custom cell Monk.
import UIKit
class Monk: UITableViewCell {
#IBOutlet weak var titleImage: UIImageView!
//other outlets defined here
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func set(_ service:Service) {
if let imgv = self.titleImage {
imgv.image = service.image
} else {
print(self.titleImage)
}
self.titleLabel.text = service.title
/*other elements set here*/
}
}
I have a feeling that I did something really, really stupid.
I've set the custom class name to Monk, and also the cell identifier to Monk, because I didn't want that confusion to be the source of the issue and making the names different didn't solve the problem.
I've even printed the values in the Service object and they match what was expected.
if let imgv = self.titleImage {
imgv.image = service.image
} else {
print(self.titleImage)
}
Prints "nil" and the error is thrown on the next line,
self.titleLabel.text = service.title
I also set the identifier and class of the nib to "Monk".
This is something simple.
If you are using a custom NIB for your cell, then you do need to register it.
Something like this in viewDidLoad:
let myNib = UINib(nibName: "MonkCell", bundle: nil)
tableView.register(myNib, forCellReuseIdentifier: "Monk")
This is unnecessary if you choose to layout the cell directly in the storyboard for your view controller.
I am using storyboard for UITableView prototype cell and set the accessoryType to Disclosure Indicator. The arrow one ">". I want to know when the arrow image was added or where can i get it correctly?
Here is the UIImageView i want to get.
My test() function below prints [], only when i scroll the tableview then it prints correct.
[<UIImageView: 0x7fc614766050; frame = (0 0; 8 13); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x618000435f00>> - (null)]
I also tried:
cellForRowAt and willDisplay, both can't get the UIImageView only if by scrolling the tableView it works.
My customize UITableViewCell class:
class TestCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
test()
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
test()
self.accessoryType
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
test()
}
func test() {
print(subviews[2].subviews)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
test()
// Configure the view for the selected state
}
}
you override layoutSubviews of the custom cell class and when that is called, delegate to super class first and then check the view hierarchy over and over till you find it.
it is the best you get. not fool proof as you deal with private view hierarchy that isnt yours ;) but it works - we did it for years.
note too that the view hierarchy can change between any iOS releases. it isnt like this is public api. so program extra defensively
I have designed a custom cell in xib. And created a class for that as well. The code for that class is as given below-
class ProjectsCell : UITableViewCell {
#IBOutlet var projectNameLabel: UILabel! //This is outlet to which I will assign value.
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Now I have a view controller there I am trying to access this cell. In storyboard I have given reusable identifier "Cell". Now I am using this cell like the following code-
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as ProjectsCell
let project = projects[indexPath.row]
cell.projectNameLabel?.text = project.ProjectName //********* Here I am getting exception for projectNameLabel.
return cell
I think that label is coming null. I have tried the following approach also but that is also not working.
var cell: ProjectsCell = tableView.dequeueReusableCellWithIdentifier("Cell") as ProjectsCell
tableView.registerNib(UINib(nibName: "ProjectsCell", bundle: nil), forCellReuseIdentifier: "Cell")
cell = tableView.dequeueReusableCellWithIdentifier("Cell") as ProjectsCell
What can be the issue if anyone has faced this same issue.
Your custom cell should inherit from the class UITableViewCell. So the class would look like this.
class ProjectsCell: UITableViewCell {
#IBOutlet var projectNameLabel: UILabel! //This is outlet to which I will assign value.
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
If you have it like this it should work. Because i am doing it like that in my Apps. For the future if you create a class you can use the 'File -> New Files...' menu. There you can select coca touch class and specify the class you want to inherit from and xcode will add all necessary functions.
You have dequeued the custom cell but not initialised it with the following method.
Besides this you also have to set your custom class as the sub-class of UITableViewCell this is because you are getting the null value for the cell.
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStylePlain reuseIdentifier: "Cell")
}
I solved the problem using the following code-
var array = NSBundle.mainBundle().loadNibNamed("ProjectsCell", owner: self, options: nil)
var cell = array[0] as ProjectsCell
let project = projects[indexPath.row]
cell.nameLabel?.text = project.Name
return cell
Thanks everyone for contributing. :)
Maybe it set the dataSource and delegate :
(source: icodeblog.com)
I'm creating a productivity app in Swift. I'm not using a prototype cell in the Storyboard as most of it has been written in code already. I'd like to a checkbox button.
How would I go about doing that?
While the answer from Tim is technically correct, I would not advise on doing this. Because the UITableView uses a dequeuing mechanism, you could actually receive a reused cell which already has a button on it (because you added it earlier). So your code is actually adding a 2nd button to it (and a 3rd, 4th, etc).
What you want to do, is create a subclass from the UITableViewCell which adds a button to itself, while it is being instantiated. Then you can just dequeue that cell from your UITableView and it will automatically have your button on it, without the need to do it in the cellForRowAtIndexPath method.
Something like this:
class MyCustomCellWithButton: UITableViewCell {
var clickButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton;
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier);
self.contentView.addSubview(self.clickButton);
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
And then you can actually dequeue it in the cellForRowAtIndexPath like this.
var cell = tableView.dequeueReusableCellWithIdentifier("my-cell-identifier") as? MyCustomCellWithButton;
if (cell == nil) {
cell = MyCustomCellWithButton(style: UITableViewCellStyle.Default, reuseIdentifier: "my-cell-identifier");
}
return cell!;
Well, first of all your cellForRowAtIndexPath should probably use the dequeue mechanism so you aren't recreating cells every time when virtualizing.
But that aside, all you need to do is create the button, and add it as a sub view to the cell.
cell.addSubview(newButton)
But of course then you will have to manage the sizing and layout as appropriate.
A UITableViewCell also has a selected state and a didSelect and didDeselect method available that listens to taps on the whole cell. Perhaps that's a bit more practical since you seem to want to check/uncheck checkboxes, which is more or less the same as selecting. You could set the cell in selected state right after you dequeued it.
I'm trying to use a custom TableViewCell Class in my programmatically created UITableView and i can't figure out why this don't get to work. I've used custom TableViewCell Classes a few times without any problems (set the Classname in Storyboard) but here i have no Storyboard to set the Class which should be used to generate the Cells.
I'm doing this:
override func viewDidLoad() {
...
self.popupTableView.registerClass(CustomTableViewCellPopup.self, forCellReuseIdentifier: "popupTableViewCell")
...
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("popupTableViewCell") as CustomTableViewCellPopup
...
return cell
}
class CustomTableViewCellPopup: UITableViewCell {
var message: UILabel = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init(coder decoder: NSCoder) {
super.init(coder: decoder)
}
override func awakeFromNib() {
super.awakeFromNib()
println("I'm running!")
self.message.frame = CGRectMake(0, 0, 10, 10);
self.message.backgroundColor = UIColor.brownColor()
self.addSubview(self.message)
}
}
The println() Output never appears. The TableView gets rendered without the additional UILabel (message). Just like an out of the box UITableViewCell.
The same way (without registerClass()) i'm running a TableView with custom Cells from the Storyboard (the Classname directly defined in the Storyboard Inspector) without any problems.
Have you an idea why the custom Class don't get used?
awakeFromNib won't get called unless the cell is loaded from a xib or storyboard. Move your custom code from awakeFromNib into initWithStyle:reuseIdentifier: because that's the initializer used by the tableView when you call its dequeueReusableCellWithIdentifier: method
You're not seeing the println output because that's in awakeFromNib, which is only called if you cell comes from a storyboard or XIB. Here you're just registering the class with the table, so there's no Nib loading going on. Try making a call to configure the cell from tableView:cellForRowAtIndexPath:, rather than configuring in awakeFromNib.
initWithCoder: won't be called for the same reason - try overriding initWithStyle:reuseIdentifier:.