Monday 2 May 2016

A Category Example on UIView

If you have ever used categories, you will probably agree if I tell you they are one of the coolest features of Objective-C. They are great for making code more readable and reusable. Here's an example of a category I recently started using because it can be quite frustrating entering:

[self.view setFrame:CGRectMake(self.view.frame.origin.x,10,self.view.frame.size.width,self.view.frame.size.height)];

just to change the y value for a view's frame. I wanted to make a category where you can do something like the following:

self.view.y = 10;

The resulting category


Here is the code in the .h file for the UIView+Frame category:

@interface UIView (Frame)
@property (nonatomic) CGFloat x;
@property (nonatomic) CGFloat y;
@property (nonatomic) CGFloat height;
@property (nonatomic) CGFloat width;
@property (nonatomic) CGSize size;

@property (nonatomic,readonly) CGFloat bottom;
@property (nonatomic,readonly) CGFloat right;
@end

You might never have heard of adding properties using categories, but they're not really properties with instance variables, they're only properties in the sense that they have a setter and a getter. The setters and getters are implemented in the .m file:

@implementation UIView (Frame)
-(CGFloat)x {
    return self.frame.origin.x;
}
-(CGFloat)y {
    return self.frame.origin.y;
}
-(CGFloat)height {
    return self.frame.size.height;
}
-(CGFloat)width {
    return self.frame.size.width;
}
-(CGSize)size {
    return self.frame.size;
}
-(void)setX:(CGFloat)x {
    [self setFrame:CGRectMake(x,self.y,self.width,self.height)];
}
-(void)setY:(CGFloat)y {
    [self setFrame:CGRectMake(self.x,y,self.width,self.height)];
}
-(void)setHeight:(CGFloat)height {
    [self setFrame:CGRectMake(self.x,self.y,self.width,height)];
}
-(void)setWidth:(CGFloat)width {
    [self setFrame:CGRectMake(self.x,self.y,width,self.height)];
}
-(void)setSize:(CGSize)size {
    [self setFrame:CGRectMake(self.x,self.y,size.width,size.height)];
}

-(CGFloat)bottom {
    return self.y + self.height;
}

-(CGFloat)right {
    return self.x + self.width;
}
@end

Notice that the getter is just the name of the property, while the setter is setName where name is the name of the property. Really straightforward.  Notice also the two properties bottom and right. I added them in for convenience, because I often need to know x or y value for the right or bottom of a view. But I never want to change the bottom or the right, so I made that property readonly.

Categories can really make life a lot easier, especially when you use properties in categories. I hope I've encouraged you to try categories a bit more.