patternswiftMinor
UIButton Subclass - Overriding getters to return placeholder/default values
Viewed 0 times
returnuibuttongetterssubclassdefaultvaluesoverridingplaceholder
Problem
I'm in the process of converting a custom
MyButton.h
MyButton.m
I have attempted to replicate this pattern in Swift with public vars which return a default value, or access a private optional variable which is returned if it exists. I have also overridden the
```
class MyButton: UIButton {
private var _buttonColor: UICo
UIButton from Objective-C to Swift which has custom properties and default values for those properties:MyButton.h
@interface MyButton : UIButton
@property (nonatomic, strong) IBInspectable UIColor *buttonColor;
@property (nonatomic, strong) IBInspectable UIColor *buttonSelectedColor;
// ...
@endMyButton.m
@implementation MyButton
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self adjustButtonColor];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self adjustButtonColor];
}
return self;
}
- (void)setSelected:(BOOL)selected
{
[super setSelected:selected];
[self adjustButtonColor];
}
- (void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
[self adjustButtonColor];
}
- (void)adjustButtonColor
{
if (self.selected || self.highlighted) {
self.backgroundColor = [self buttonSelectedColor];
} else {
self.backgroundColor = [self buttonColor];
}
}
#pragma mark - Default colors
- (UIColor *)buttonColor
{
if (!_buttonColor) {
_buttonColor = [UIColor grayColor];
}
return _buttonColor;
}
- (UIColor *)buttonSelectedColor
{
if (!_buttonSelectedColor) {
_buttonSelectedColor = [self.buttonColor colorWithAlphaComponent:.5];
}
return _buttonSelectedColor;
}
#pragma mark - Public
- (void)setButtonColor:(UIColor *)buttonColor
{
_buttonColor = buttonColor;
[self updateButton];
}
@endI have attempted to replicate this pattern in Swift with public vars which return a default value, or access a private optional variable which is returned if it exists. I have also overridden the
selected and highlighted properties, updating the button colors in didSet:```
class MyButton: UIButton {
private var _buttonColor: UICo
Solution
Is this an appropriate use of private variables? Is there any way to accomplish the behavior I want with a single variable rather a second optional settable variable for each color?
This can be much easier accomplished with a lazy stored property:
The right-hand side is evaluated exactly once, when the property
is accessed the first time. This makes the private
obsolete. (I think that you seldom need such a "shadow copy" in Swift.)
But there seems to be no real need for
lazily. If you make it an ordinary stored property then you can add
a property observer:
If you want
it needs to be a lazy property, otherwise you could make it a stored
property as well:
Is overriding UIButton properties to call adjustButtonColor in didSet abuse of the getter/setter?
That is fine. The Swift reference explicitly states: "You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass."
If initWithCoder is a failable initializer do I need to check if self is nil before calling adjustButtonColor()?
You don't need to (and you can't). If
fails then your
is not reached.
This can be much easier accomplished with a lazy stored property:
lazy var buttonColor: UIColor = UIColor.grayColor()
lazy var buttonSelectedColor: UIColor = self.buttonColor.colorWithAlphaComponent(0.5)The right-hand side is evaluated exactly once, when the property
is accessed the first time. This makes the private
_xxx variablesobsolete. (I think that you seldom need such a "shadow copy" in Swift.)
But there seems to be no real need for
buttonColor to be evaluatedlazily. If you make it an ordinary stored property then you can add
a property observer:
var buttonColor = UIColor.grayColor() {
didSet {
self.updateButton()
}
}If you want
buttonSelectedColor to be computed from buttonColor then it needs to be a lazy property, otherwise you could make it a stored
property as well:
var buttonSelectedColor = UIColor.grayColor().colorWithAlphaComponent(0.5)Is overriding UIButton properties to call adjustButtonColor in didSet abuse of the getter/setter?
That is fine. The Swift reference explicitly states: "You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass."
If initWithCoder is a failable initializer do I need to check if self is nil before calling adjustButtonColor()?
You don't need to (and you can't). If
super.init(coder: aDecoder)fails then your
init?(coder:) method fails immediately, and the next statementis not reached.
Code Snippets
lazy var buttonColor: UIColor = UIColor.grayColor()
lazy var buttonSelectedColor: UIColor = self.buttonColor.colorWithAlphaComponent(0.5)var buttonColor = UIColor.grayColor() {
didSet {
self.updateButton()
}
}var buttonSelectedColor = UIColor.grayColor().colorWithAlphaComponent(0.5)super.init(coder: aDecoder)Context
StackExchange Code Review Q#131554, answer score: 3
Revisions (0)
No revisions yet.