How do I set an initializer for a custom UITableViewCell class? - ios

I've searched around for an answer to this, but each solution just brings new compiler errors.
How do I set up the initializers for a class that inherits from UITableViewCell?
This is what I have so far, any help would be greatly appreciated:
SettingCell.swift
class SettingCell: UITableViewCell {
#IBOutlet weak var settingsLabel: UILabel!
#IBOutlet weak var settingsSwitch: UISwitch?
#IBOutlet weak var timeSetting: UILabel?
var cellDelegate: SettingCellDelegate?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
init(settingLabel: UILabel!, settingSwitch: UISwitch?, timeSetting: UILabel?) {
super.init(style: UITableViewCellStyle, reuseIdentifier: String?)
self.settingsLabel = settingLabel
self.settingsSwitch = settingSwitch
self.timeSetting = timeSetting
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#IBAction func handledSwitchChange(sender: UISwitch) {
self.cellDelegate?.didChangeSwitchState(sender: self, isOn:settingsSwitch!.on)
}
...
}
Fix-It Error:
Compiler Error:
'UITableViewCellStyle.Type' is not convertible to 'UITableViewCellStyle'

When you call this line:
super.init(style: UITableViewCellStyle, reuseIdentifier: String?)
you need to supply an actual cell style and an actual reuse identifier. You code at the moment is written as if this line is a function definition, not a function invocation.
Change it to something like:
super.init(style: .Default, reuseIdentifier: "SettingCell")
(though preferably at least the reuse identifier should be provided by the caller, not statically)

Related

Set data in UITableViewCell

I try use UITableViewCell. My custom cell has StackView's and other views.
I need to send object from controller (UITableViewController) for next parsing it.
in cell I set field:
class MyCell: UITableViewCell {
var myObject : MyObject?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
in this I try get data from my object
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
and in my Controller I write:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// create a new cell if needed or reuse an old one
let cell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as MyCustomCell!
cell.myObject = self.arrayMyObjects[indexPath.row]
return cell
}
But everytime I have nil in my cell. Why?
In your cell init is to early to try and access myObject. You should use a didSet on the property to make the changes when it's assigned a new value.
var myObject : MyObject? {
didSet {
// Update your subviews here.
}
}

Property 'self.delegate' not initialised at super.init

I am trying to make a protocol in a UITableViewCell class but when i declare my delegate, I get an error in both required init?(coder aDecoder: NSCoder) and override init(style: UITableViewCellStyle, reuseIdentifier: String?)
Error : - Property 'self.delegate' not initialised at super.init
This is my subclass:-
import UIKit
protocol tableCellBtnActionDelegate{
func removeRowAtIndex(_: Int)
}
class FriendsListTableViewCell: UITableViewCell {
#IBOutlet weak var friendListAddBtn: UIButton!
var usersId : String!
var buttonText : String!
var indexPath : Int!
let delegate : tableCellBtnActionDelegate!
override func awakeFromNib() {
super.awakeFromNib()
friendListAddBtn.layer.cornerRadius = 4
friendListAddBtn.layer.backgroundColor = UIColor(red: 121.0/255.0, green: 220.0/255.0, blue: 1, alpha: 1).CGColor
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
}
Well you haven't initialize it, so the compiler gives you a warning.
I would advise you to modify the delegate to be optional and set your delegate whenever you need it.
var delegate : tableCellBtnActionDelegate?
You should also handle the case where delegate is not set(nil).
Change
let delegate : tableCellBtnActionDelegate!
to
var delegate : tableCellBtnActionDelegate!
or you can't set value to delegate property ever
You got a warning because you are not initialising the delegate property. It should actually be a weak property, or you will retain a reference to the delegate object, which you usually don't want to do. So the best approach would be:
weak var delegate : tableCellBtnActionDelegate?
And then you have to use it like this:
self.delegate?.notifyAboutSomething()

How to initialize customized UITableViewCell ui-related property

I am created a custom UITableViewCell and added some outlet fields which connect to the UI elements on storyboard. Please see below as an example. But I always got nil pointer exception on the line "self.skillBtn.backgroundColor = UIColor.redColor()" in "required init?(coder aDecoder: NSCoder) " method. It means that the skillBtn has not been initialized yet. I wander where I should do the UI initialization on a UITableViewCell?
#IBOutlet weak var backgroundImg: UIImageView!
#IBOutlet weak var userNameLabel: UILabel!
var delegate: UserHomeCategorySelectionDelegate?
#IBOutlet weak var skillBtn: UserHomeCategoryButton!
#IBOutlet weak var speakBtn: UserHomeCategoryButton!
#IBOutlet weak var friendsBtn: UserHomeCategoryButton!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.skillBtn.backgroundColor = UIColor.redColor()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.skillBtn.backgroundColor = UIColor.redColor()
}
Thats because the views are not yet connected from your Storyboard/XIB to your class instance,
to achieve what you want, override awakeFromNib method and put self.skillBtn.backgroundColor = UIColor.redColor() inside it.
awakeFromNib is called after view is loaded from the XIB/Storyboard and outlets are connected.

UITableView with custom cells is empty

I have a two custom cells implemented:
class TextFieldCell: UITableViewCell{
var label = UILabel()
var textField = UITextField()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
label.text = "Name"
textField.placeholder = "Enter Task Name Here"
addSubview(label)
addSubview(textField)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
class SwitchCell : UITableViewCell {
var label = UILabel()
var switchControl = UISwitch()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
label.text = "State"
switchControl.on = true
addSubview(label)
addSubview(switchControl)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
In my table view class i have declared this two cells:
let textFieldCell = TextFieldCell(style: .Default, reuseIdentifier: "textFieldCell")
let switchCell = SwitchCell(style: .Default, reuseIdentifier: "switchCell")
and have delegate method in it:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch indexPath.row {
case 0: return textFieldCell
case 1: return switchCell
default: return UITableViewCell()
}
}
But when table view loads i've see only switch control on the left of second row. I don't know why.
Try this:
private let reuseIdentifier = "switchCell"
//identifier of your cell.
Seems you have missed registering the cell.
let tableNib = UINib(nibName:"SwitchCell", bundle:nil)
self.tableView!.registerNib(tableNib,forCellReuseIdentifier:reuseIdentifier)
TextFieldCell Added below Code in ViewDidLoad of TableViewCell
self.tableView.registerClass(SwitchCell, forCellReuseIdentifier: "switchCell")
self.tableView.registerClass(TextFieldCell, forCellReuseIdentifier: "textFieldCell")

Swift. Proper initialization of UITableViewCell hierarchy

[UITableViewCell] <- [genericCell] <- [Cell1], [Cell2], [Cell3]
Hello. Please imagine hierarchy above. In my code I don't have objects exactly of type genericCell, but this class shares some properties.
What design of inits should be in my code? I have following structure for genericCell:
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
//my stuff (initializing shared properties)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
But what about Cell1? How can I invoke init(style: UITableViewCellStyle, reuseIdentifier: String?) in genericCell for "my stuff" operations through initialisation of Cell1 instance? Now they doesn't perform.
EDIT
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let typeOfCell = FbDataManager.sharedInstance.posts[indexPath.row][FbDataManager.sharedInstance.typeParameter] as! String
switch typeOfCell {
case self.linkTypeOfPost:
var cell = tableView.dequeueReusableCellWithIdentifier(self.linkCellIdentifier) as? FbLinkPostViewCell
if cell == nil {
cell = FbLinkPostViewCell.init(style: .Default, reuseIdentifier: self.linkCellIdentifier)
}
//...
Hi again. This is part from tableView's delegate, btw I copy-pasted Abhinav's inits to my code and again those inits aren't working. (no output to console)
I'm not sure I understand your question correctly, but it seems to be about inheritance between classes. So basically you have a "GenericCell" class that inherits from "UITableViewCell", and "CellOne", "CellTwo", and "CellThree" classes that each inherit from "GenericCell". If you want to go through init with style, one way to set this up would be like this:
class GenericCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// code common to all your cells goes here
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
class CellOne: GenericCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier) // the common code is executed in this super call
// code unique to CellOne goes here
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
You could then create instances of CellOne in your table view's data source like so:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell")
if (cell == nil) {
cell = CellOne.init(style: .Default, reuseIdentifier: "cell")
}
return cell!
}
For each instance it will now first go through the common setup done in "GenericCell", and then through the unique setup in "CellOne". "CellTwo" and "CellThree" would be set up accordingly.
EDIT
A more concrete example of how to configure instances of all three Cell types:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// you need to write a method like this to figure out which type you need:
let cellID = self.cellIDForIndexPath(indexPath) // returns either "cell1", "cell2" or "cell3"
// dequeue or init a cell of the approriate type
var cell = tableView.dequeueReusableCellWithIdentifier(cellID)
if (cell == nil) {
switch cellID {
case "cell1": cell = CellOne.init(style: .Default, reuseIdentifier: "cell")
case "cell2": cell = CellTwo.init(style: .Default, reuseIdentifier: "cell")
case "cell3": cell = CellThree.init(style: .Default, reuseIdentifier: "cell")
default: cell = UITableViewCell()
}
}
// configure the individual cell if needed (you need to implement methods + logic here that fit your data)
(cell as! GenericCell).configureForData(self.dataForIndexPath(indexPath))
return cell!
}
This is how I would lay down the hierarchy mentioned by you:
Step 1 : Make Generic Cell class
class GenericCell : UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
print("Generic Cell Initialization Done")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Step 2 : Make Specific Cell 1 class:
class MyCell1 : GenericCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
print("MyCell1 Initialization Done")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Step 3 : Make Specific Cell 2 class:
class MyCell2 : GenericCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
print("MyCell2 Initialization Done")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Step 4 : Make Specific Cell 3 class:
class MyCell3 : GenericCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
print("MyCell3 Initialization Done")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Step 5 : Finally use the cells like this:
let cell1 = MyCell1.init(style: UITableViewCellStyle.Default, reuseIdentifier: "cell1")
let cell2 = MyCell2.init(style: UITableViewCellStyle.Default, reuseIdentifier: "cell2")
let cell3 = MyCell3.init(style: UITableViewCellStyle.Default, reuseIdentifier: "cell3")
PS: This would guarantee setting the properties in generic cell as well in specific cells.
EDIT: This is how you would use cells in cellForRowAtIndexPath:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell1 = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as MyCell1
if cell1 == nil {
cell1 = MyCell1.init(style: UITableViewCellStyle.Default, reuseIdentifier: "cell1")
}
// Do your cell property setting
return cell1
} else if indexPath.section == 1 {
let cell2 = tableView.dequeueReusableCellWithIdentifier("cell2", forIndexPath: indexPath) as MyCell2
if cell2 == nil {
cell2 = MyCell2.init(style: UITableViewCellStyle.Default, reuseIdentifier: "cell2")
}
// Do your cell property setting
return cell2
} else {
let cell3 = tableView.dequeueReusableCellWithIdentifier("cell3", forIndexPath: indexPath) as MyCell3
if cell3 == nil {
cell3 = MyCell3.init(style: UITableViewCellStyle.Default, reuseIdentifier: "cell3")
}
// Do your cell property setting
return cell3
}
}

Resources