@implementation UIButton (ColorButton)
+(instancetype)buttonWithColor:(UIColor*)color {
UIButton* button = [[self.class alloc] initWithFrame:CGRectZero];
...
return button;
}
The Problem
This situation came up recently when I had a category class method that made a button with a certain background colour, but I wanted to customise the button to change background colour when it was highlighted or in the touch down state.The category looked like this:
@implementation UIButton (ColorButton)
+(UIButton)buttonWithColor:(UIColor*)color {
UIButton* button = [[UIButton alloc] initWithFrame:CGRectMake(0,0,UIScreen.mainScreen.bounds.size.width,50)];
button.backgroundColor = color;
return button;
}
@end
This method takes a UIColor and returns a UIButton with a size and colour.
In the subclass, I needed to override the setHighlighted: method:
@implementation ColorButton
- (void) setHighlighted:(BOOL)highlighted {
[super setHighlighted:highlighted];
if (highlighted) {
self.backgroundColor = self.colour_selected;
}
else {
self.backgroundColor = self.colour;
}
}
@end
This allows me to pick two colours colour_selected and colour to be the tap down and tap up colours respectively. I tried using my new subclass with:
ColorButton* button_new = [ColorButton buttonWithColor:[UIColor whiteColor]];
button_new.colour = [UIColor whiteColor];
button_new.colour_selected = [UIColor grayColor];
However when I tried to compile this code and I got the following warning:
This allows me to pick two colours colour_selected and colour to be the tap down and tap up colours respectively. I tried using my new subclass with:
ColorButton* button_new = [ColorButton buttonWithColor:[UIColor whiteColor]];
button_new.colour = [UIColor whiteColor];
button_new.colour_selected = [UIColor grayColor];
However when I tried to compile this code and I got the following warning:
incompatible pointer types assigning to 'ColorButton *' from 'UIButton *'
The first fix
Okay. I tried changing +(UIButton)buttonWithColor:(UIColor*)color to+(instancetype)buttonWithColor:(UIColor*)color. Now the code compiled and ran, but it crashed when it tried to set the colour property on button_new.
The second fix
It crashed because button_new was actually a UIButton and not a ColorButton. To fix this I needed to look at the code in the buttonWithColor: method a little closer.@implementation UIButton (ColorButton)
+(instancetype)buttonWithColor:(UIColor*)color {
UIButton* button = [[UIButton alloc] initWithFrame:CGRectMake(0,0,UIScreen.mainScreen.bounds.size.width,50)];
button.backgroundColor = color;
return button;
}
@end
Notice the call to alloc is for a UIButton. How did I make it work for the current class just like I did with instancetype? I replaced the UIButton with self.class:
@implementation UIButton (ColorButton)
+(instancetype)buttonWithColor:(UIColor*)color {
UIButton* button = [[self.class alloc] initWithFrame:CGRectMake(0,0,UIScreen.mainScreen.bounds.size.width,50)];
button.backgroundColor = color;
return button;
}
@end
And that's it. The code runs and the button changes colour when it's tapped. But what is self in this case and what does self.class do? I guess that question could be a topic for another blog post.
No comments:
Post a Comment