How to subclass custom UITableViewCell? - ios

I am trying to create a UITableView with 3 different custom UITableViewCell. They all share some common elements such as a UILabel that is called questionLabel.
I have three types of cells
OneTextFieldTableViewCell
TwoLabelTableViewCell
ThreeLabelTableViewCell
I want these cells to inherit from a FormTableViewCell that share common UI elements like the questionLabel as mentioned above.
Code:
class OneTextFieldTableViewCell: FormItemTableViewCell {
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet weak var answerTextField: UITextField!
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
}
}
FormItemTableViewCell
class FormItemTableViewCell: UITableViewCell {
#IBOutlet weak var questionLabel: UILabel!
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
}
}
I am getting errors:
Cannot override with a stored property 'questionLabel'
Getter for 'questionLabel' with Objective-C selector 'questionLabel' conflicts with getter for 'questionLabel' from superclass 'FormItemTableViewCell' with the same Objective-C selector
Setter for 'questionLabel' with Objective-C selector 'setQuestionLabel:' conflicts with setter for 'questionLabel' from superclass 'FormItemTableViewCell' with the same Objective-C selector

Your variable questionLabel is already defined in your superclass. No need to mention it again. That's the whole point of inheritance. Your subclasses inherit the variables of its super classes.
IBOutlet, IBAction, IBDesignable are just labels. Doesn't matter where you add them in the inheritance tree. Once there, you have informed the compiler/Xcode that this is a "special" function or variable.
So if your class has a function #IBAction func doStuff() , you can override it as override func doStuff() and still connect to it from within IB. Same for overriding IBOutlet in case you want to add willSet or didSet or replace the getter/setter functions.

Related

Custom cells with common features in ios

I have an app in which I have a tableview. Inside this tableview I currently have 8 different types of cells. Each of these cells are different but also have similarities.
As an example (using only 2 cells for simplicity). Imagine you have cell 1 which can be divided into 3 parts:
--------------A--------------
--------------B--------------
--------------C--------------
Now cell 2 also has 3 parts. Parts A and C are the same as in cell1 (different data of course, but same structure):
--------------A--------------
--------------D--------------
--------------C--------------
Currently, in my cellForRowAt method I just check if the cell type should be 1 or 2 and then I dequeue cell for that type. The challenge is that I would like to avoid setting part A and C two different places in the code.
Eg. instead of
if type == type1 {
//Set A
//Set B
//Set C
} else if type == type2 {
//Set A
//Set D
//Set C
}
I would like
//Set A
//Set C
if type == type1 {
//Set B
} else if type == type2 {
//Set D
}
I was wondering if there is a way to "abstract" these commonalities?
Please let me know if anything is unclear.
EDIT: IB Challenge
I probably should also mention that a tricky part for me is figuring out how a parent cell would fit in in regards to IB. I have separate xib files for each cell type, but if I would only have one parent swift file with section A and C, can both my other xib files have the same outlets to this parent and how would this even be done?
Parent TableViewCell
class BaseTableViewCell: UITableViewCell {
#IBOutlet weak var ALabel: UILabel!
#IBOutlet weak var CLabel: UILabel!
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
}
}
Subclass of BaseCell
class TypeOneTableViewCell: BaseTableViewCell {
#IBOutlet weak var BLabel: UILabel!
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
}
}

make UITableView updates from class of the cells populating it

I have used the same nib file to populated a UITableView. There are 2 different functionalities I have built out for these cells. If you anywhere on the cell other than a small button it runs a function and segues to another page. However if you click the small button, I want to update the UITableView and input a cell below the clicked cell, as a sort of dropdown. I have the below to successfully run a separate functionality:
import UIKit
class ContactCell: UITableViewCell {
//below are the outlets for the conact cells
#IBOutlet weak var msgStatus: UIView!
#IBOutlet weak var contactName: UILabel!
#IBOutlet weak var dropDown: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
msgStatus.layer.cornerRadius = msgStatus.frame.size.width/2
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
#IBAction func dropDown(_ sender: Any) {
print("selected drop down")
}
}
Moving forward I need to be able to get the index of the current cell and perform a UITableView update from the UITableViewCell's class. How would I be able to do this?
You could do this with delegation. Create a delegate protocol for your ContactCell:
protocol ContactCellDelegate {
func pleaseAddDropdown(to: ContactCell)
}
Then set up a delegate parameter for the cell:
var delegate: ContactCellDelegate?
Then subscribe your table view to the ContactCellDelegate protocol (you will have to subclass if you are using a standard UITableView). This means you will need to write an implementation of pleaseAddDropdown() for your table view class. When you dequeue a cell make sure the delegate parameter is assigned to your table view.
Now in your implementation of dropdown() you just need to do something like:
guard let _ = delegate else { return }
delegate!.pleaseAddDropdown(to: self)
Which will send that message up to the table view which can take the appropriate action.
Hope that helps.

Setting delegate for UITextField produces error

I have a table view with prototype cells and a custom table view cell class. In one of the prototype cells I have a UITextField. I'm trying to dismiss the keyboard when the return key is pressed, to do that I'm using the function textFieldShouldReturn and am trying to set the delegate of my UITextView to self(inputText.delegate = self). Unfortunately, without setting the delegate to self results in nothing happening when return is pressed, and with the inputText.delegate = self line the app crashes with the error fatal error: unexpectedly found nil while unwrapping an Optional value.
Here is my custom table view cell file.
import UIKit
class CustomTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var inputLabel: UILabel!
#IBOutlet weak var inputText: UITextField!
#IBOutlet weak var labelLabel: UILabel!
#IBOutlet weak var labelDetail: UILabel!
#IBOutlet weak var picker: UIPickerView!
#IBOutlet weak var largeInputText: UITextField!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
inputText.delegate = self
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
print("return button in CustomTableViewCell")
inputText.resignFirstResponder()
return true
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Any help would be greatly appreciated.
There could one of these reasons because of which you are getting this error.
You might not have specified the class of your prototype cell in interface builder. See below
You might not have correctly set the IBOutlet property. Check this in last tab on the side bar shown above after clicking on the label in your prototype cell.
NOTE: Make sure that you have set the custom class for your table view controller or view controller as well.
tryn to call awakeFromNib() from viewDidLoad() ; and then you can select what type of keyboard need for edit : inputTextFile.keyboardType = UIKeyboardType.ASCIICapable/EmailAddress/etc

Delegate error for UIStepper in TableViewCell and TableViewController

I have an issue with my delegate for UIStepper, TableViewCell and TableViewController. I am unable to pass a delegate command to my TableViewCell in the TableViewController.
My TableViewCell code is as below:
CampTableCell.swift
import UIKit
protocol ReviewCellDelegate{
func stepperButton(stepper_value:Int)
}
class CampTableCell: UITableViewCell {
#IBOutlet var campqty: UILabel!
#IBOutlet var stepper: UIStepper!
var delegate:ReviewCellDelegate!
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
}
#IBAction func stepperValueChanged(sender: UIStepper) {
self.delegate.stepperButton(Int(stepper.value))
campqty.text = String(Int(stepper.value))
}
}
The start of my TableGenController.swift is this:
class TableGenController: UITableViewController, UISearchBarDelegate, ReviewCellDelegate {
and I have added this function (as a test):
func stepperButton(stepper_value:Int) {
print("Value Changed!")
}
Next, I believe, is I have to add this under viewDidLoad:
CampTableCell.delegate = self
However, this causes an error stating that:
Instance member 'delegate' cannot be used on type 'CampTableCell'
I might be doing something conceptually wrong, but it's been difficult to find resources for this particular setup. Would be really grateful for some help on this, thanks!
I'm not proficient in delegates, but have you tried removing the line with the error? I'm not sure you need it.
Also I think you can remove self in
self.delegate.stepperButton(Int(stepper.value))

keep UISwitch state of a prototype cell when changing ViewControllers

I have a UITableViewCell subclass where I have connected a UISwitch from a custom prototype cell. (data are passed in the Table View from a previous ViewController)
When I Change view controllers the state of the UISwitchchanges back to default
I need some way to remember the state of the switch while navigating through the app.
I have searched a few other topics, but nothing seemed to fall in my case.
Here is the code:
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var myStaticSwitch: UISwitch!
#IBOutlet weak var cellLabel: UILabel!
#IBAction func mySwitch(sender: UISwitch) {
if myStaticSwitch.on {
self.cellLabel.text = "on"
//Do other things
}
else {
self.cellLabel.text = "off"
//Do other things
}
}
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
}
}
You should have a model object that is used to determine the state of the UI representing it. This object can be saved to disk, persisted with Core Data, or even synced to a remote web service.
When you next encounter a need to display any UI related to the object, you can always check its properties to determine what to show. Your UI action method then simply updates the model representation:
#IBAction func mySwitch(sender: UISwitch) {
myModelObject.enabled = myStaticSwitch.on
}
The UI (e.g., your table cell) then looks for changes to enabled and updates the cellLabel as needed.
here is the code. Now I need a way to refer to each Switch separately and not as a whole.
import UIKit
class TableViewCell: UITableViewCell {
#IBOutlet weak var myStaticSwitch: UISwitch!
#IBAction func mySwitch(sender: UISwitch) {
myStaticSwitch.on = (sender as UISwitch).on //Bool
NSUserDefaults.standardUserDefaults().setBool(myStaticSwitch.on, forKey: "autoAdjustSettings")
NSUserDefaults.standardUserDefaults().synchronize()
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
myStaticSwitch.on = NSUserDefaults.standardUserDefaults().boolForKey("autoAdjustSettings")
// Configure the view for the selected state
}
}

Resources