Let's say we have a generic UITableViewCell:
class ControlTableViewCell<ControlType: UIControl>: UITableViewCell
Because when we need to create the cell we need to know the control type, we should disable this initializer:
#available(*, unavailable)
override convenience init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
fatalError("Use init().")
}
and only use the following initializer:
init(with control: ControlType, reuseIdentifier: String? = nil) {
self.control = control
super.init(style: .default, reuseIdentifier: reuseIdentifier)
configureForControl()
}
If I create a class that I want to use:
class DogTableViewCell: ControlTableViewCell<UIButton>
how would I go about dequeuing the reusable cells?
I would register first:
tableView.register(DogTableViewCell.cellClass,
forCellReuseIdentifier: DogTableViewCell.cellReuseIdentifier)
And then in the cellForRowAt:
let cell = tableView.dequeueReusableCell(withIdentifier: DogTableViewCell.cellReuseIdentifier,
for: indexPath) as? DogTableViewCell ?? DogTableViewCell()
But because dequeueReusableCell uses init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) we would crash at fatalError("Use init().")
Is there a good way to deal with this situation? I found a number of posts that ask the same question, but they all seem to want to set some properties that can be set later on, so no point in trying to use a custom initializer when dequeueing.. but in my case the class being generic, it needs to be initialized with a type.
Thanks for your help.
Similar posts: UITableViewCell dequeueReusableCellWithIdentifier with custom initializer
You should remove all your initializers and add call configure method after the cell is created. For example,
func setControl(control: ControlType) {
self.control = control
configureForControl()
}
Call this methods after dequeueReusableCell
Related
I have a UITableView containing cells which need different accessory types. At the moment I have the standard arrow accessory type from Swift. I want to set an accessory type or a checkbox at the right position inside the cell. How can I achieve this?
I have a ViewController class where I specify the information:
struct customCell {
let title: String
}
func configure() {
models.append(Section(title: "", options: [
customCell(title: "Sounds"){
},
}
And I have a different UITableViewCell class where I define whats needed:
private let label: UILabel = {
let label = UILabel()
label.numberOfLines = 1
return label
}()
Right now it specifies the accessory type for all cells:
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
accessoryType = .disclosureIndicator
}
You can either add a checkbox in the Cell or use UITableViewCell accessoryView. For example:
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
accessoryView = UISwitch()
}
https://developer.apple.com/documentation/uikit/uitableviewcell/1623219-accessoryview
I've looked around and I can't find any examples of this. I simply want to create a custom initializer on a programmatic UITableViewCell subclass that includes one property.
class CustomCell: UITableViewCell {
var foo: Foo
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// custom init with a foo
}
What I want is:
let cell = CustomCell(foo: myFoo) // other default init params if needed
Not:
let cell = CustomCell()
cell.foo = myFoo
Pointing me to a resource (if I missed one) that shows an implementation like this would be great. I assume this is a common need, but a couple hours being yelled at by init compiler errors and a few Medium articles later and I can't find anything.
Instances of UITableViewCell are created by the system, using the classic init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) initializer.
Don't forget to add this magic line after initializing your UITableView:
myTableView.register(CustomCell.self, forCellReuseIdentifier: Constant.myCellReuseIdentifier)
Let's say you write this:
class CustomCell: UITableViewCell {
convenience init(reuseIdentifier: String, customObject: Any?) {
self.init(style: UITableViewCell.CellStyle.default, reuseIdentifier: reuseIdentifier)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Then you can create a cell with this line of code:
let cell = CustomCell(reuseIdentifier: Constant.myReuseIdentifier, customObject: nil)
... but what will you do with this cell? How to plug it into your "tableview's cells management" logic.
To inject something to your cell, you may plug in:
tableView(_:cellForRowAt:) for a UITableView (in the object implementing UITableViewDataSource)
collectionView(_:cellForItemAt:) or collectionView:willDisplayCell:forItemAtIndexPath: for a UICollectionView.
Those 3 methods may be call very frequently by the system, avoid memory allocations or any memory / CPU intensive task when possible.
I have created custom tableViewCell,and I don't understand why do i need to init it 2 times , override init and super.init ,what this code does, please explain
class tablecell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
}
}
This: super.init(style: .subtitle, reuseIdentifier: reuseIdentifier) doesn't mean you are initing two times.
super allows us to use the defaults of the table view cell with our custom code to work with.
So super says that: I'll use my own code with defaults.
More info: What exactly is super in Objective-C?
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:.
I've created a custom class that inherits from PFTableViewCell and for some reason the imageView is nil. Anybody know what the issue could be? I'm dequeuing the cell from the storyboard. When I completely programmatically generated the class it was fine. Here's my code.
PFTableViewCell has a property called imageView that should've been auto initialized from a child class (I thought).
class PhotoVC: PFQueryTableViewController
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!, object: PFObject!) -> PFTableViewCell! {
let CellIdentifier = "Cell"
var cell : PhotoCell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier) as PhotoCell!
if cell == nil {
cell = PhotoCell(style: .Default, reuseIdentifier: CellIdentifier)
}
println(cell.imageView) //Always prints nil
}
class PhotoCell: PFTableViewCell
init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
When I try to add an IBOutlet for the imageView I get an error.
As far as I know, the PFTableViewCell does not work well with standard styles. I took a glance at their code (it's open-source), and the comments indicate that they indeed have issues with imageView in the standard styles.
I suggest that you create a custom cell with an imageView that you need to set as a PFImageView in the storyboard.
Then the whole PFTableViewCell loading works fine (that's the only way it worked for me).