While building the Go Fit Yourself app (release date Fall 2013) for the Last Woman Standing documentary, I started collecting my own library of time savers and utilities for making my time in xCode more pleasant. My collection began to grow and eventually we transformed it into an in-house framework full of useful classes and category extensions for accelerating our app development process. Today I want to offer a little peak under the hood of our still-under-construction framework regarding one of the most common classes in iOS: UIViews.

UIViews

What is a UIView? If you've begun playing around with app development, you have no doubt heard of MVC or model-view-controller, one of the dominant design paradigms for software development. Views represents a piece of the graphical user interface of an app. They are the elements that you interact with: buttons, labels, images, sliders. Even the entire window is a view. UIView is an Objective-C class that defines the behavior for all of these awesome widgets.

Unless you are working entirely in OpenGL, when building an iOS app you will inevitably have to work with UIViews. Given a sufficiently complex app, it is more than likely that you will be dealing with dozens upon dozens of them all interlocked in diverse hierarchies and layouts.

In all honesty, one can hardly complain about Apple's current implementation of views. The hierarchy system is fantastic for designing views, propagating gesture events and animation. It really is well designed compared to numerous previous languages (remember having to manually figure out what the user clicked on?). That said, given the frequency of use of these objects, there are a handful of basic, repetitive tasks that require just a little bit too much effort at times. For example, basic tasks like aligning the view a certain way might require multiple lines of code (or overly long lines of code) for no particular reason.

/* Align view to the right top of the screen */

//get the value of parent view edge
int rightEdge = self.view.bounds.origin.x + self.view.bounds.size.width;
int topEdge = self.view.bounds.origin.y;

//set child view position (option 1)
CGRect oldFrame = myView.frame;
oldFrame.origin.x = rightEdge - oldFrame.size.width;
oldFrame.origin.y = topEdge;
myView.frame = oldFrame;

//OR (option 2)
	  myView.frame = CGRectMake(rightEdge - myView.frame.size.width, topEdge, myView.frame.size.width, myView.frame.size.height);

That is a lot of writing for changing only one or two fields, no? This could certainly be wrapped into a more reusable function or method.

Category Extensions Are Awesome

(if you already know about Categories, feel free to skip this section) The most obvious way of improving on the functionality of a class is to subclass it.

//BetterView.h

@interface BetterView : UIView
//declare new functions
-(void)foo;
@end

//BetterView.m

@implementation BetterView
//implement new functions
-(void)foo{}
@end

This approach would allow us to add all sorts of helpful goodies to any custom views we create that subclass the BetterView class. While certainly an improvement, we are still left with one gaping issue: none of your additions will apply to the built-in iOS views. You won't save any time when dealing with UILabels, UIButtons, UITables, UIImages, UISlider, vanilla UIViews or any other Apple-provided class. Chances are you will need those too. You could rewrite your own version of each iOS view class which subclasses your BetterView class, but that would be a massive undertaking.

Luckily, Objective-C has a very useful feature that can provide us with a better alternative: Category Extensions. These allow us to inject methods into a class after the class has already been declared. Instead of the above code, we could use something like the following.

//UIView+BetterView.h
@interface UIView (BetterView)
//declare new functions
-(void)foo;
@end

//UIView+BetterView.m
@implementation UIView (BetterView)
//implement new functions
-(void)foo{}
@end

Though this might look similar to the previous configuration, it works very differently. This code creates an extension on the UIView class itself. This also means any subclasses of UIView will inherit the methods you define. You can now call the foo method on any UIView, including on any subclass of UIView. This is why categories are awesome. I'm not really aware of any other language that allows such a useful behavior. The closest comparison I can think of is the JavaScript prototype chain.

Before we move on to the snippets you that may want to add to your UIViews, here are a couple of notes on using extensions:

Layout Helpers

Alright, down to business now. Here are some of the useful snippets I have been assembling

Positioning

Since, I tend to set up all of my layouts programmatically (I find the storyboard feature gets clunky), I frequently need to set the frame of my views. As noted in the first example at the top, that can require a lot of writing. The depth of the CGRect struct can result in a lot of typing. However, the worst part is that due to the way pointers work with structs, you cannot simply change one field (say frame.origin.width). You have to assign a completely new CGRect to the frame property. To do this, you need to use one of the two approaches shown in the first example of this post.

To remedy this situation, I created a set of extra properties on all UIViews to access these fields individually.

//UIView+layout.h
@interface UIView (layout)

//-----------------------------
#pragma mark - View Positioning
//-----------------------------

//accessors for inidividual fields
@property (nonatomic) CGFloat viewWidth;		//view.frame.size.width
@property (nonatomic) CGFloat viewHeight;		//view.frame.size.height
@property (nonatomic) CGFloat viewX;			//view.frame.origin.x
@property (nonatomic) CGFloat viewY;			//view.frame.origin.y
@property (nonatomic) CGPoint viewOrigin;		//view.frame.origin
@property (nonatomic) CGSize  viewSize;			//view.frame.size
@property (nonatomic) CGFloat viewRightEdge;	//view.frame.origin.x + view.frame.size.width
@property (nonatomic) CGFloat viewBottomEdge;	//view.frame.origin.y + view.frame.size.height

@end
//UIView+layout.m
@implementation UIView (layout)

//-----------------------------
#pragma mark View Positioning
//-----------------------------

-(CGFloat)viewWidth{
	return self.frame.size.width;
}

-(void)setViewWidth:(CGFloat)viewWidth{
	CGRect rect = self.frame;
	rect.size.width = viewWidth;
	self.frame = rect;
}

//etc.

@end

(For the sake of brevity, I'm only showing one property implementation here. I'll include the final file at the end of this article with the rest.)

Why a property and not simply a method such as -(void) setX? Even though the setter is far more useful to me, the getter can also save typing time. It also allows the use of either of the following syntaxes (nothing major, but handy):

int foo = myView.viewX;
//OR
int foo = [myView ViewX];

Another useful getter for positioning that I found myself frequently desiring was the center of the view itself. UIView already provides the center property for accessing the middle of the view's frame. However, when trying to position a view's subviews, it is better to position relative to the view's bounds instead. We don't need a setter here since bounds are rarely manipulated directly (that's what frame is for).

//in .h file
//get the point at the center of the view's bounds
-(CGPoint) boundsCenter;

//in .m file
-(CGpoint) boundsCenter{
	return CGPointMake(self.bounds.origin.x+self.bounds.size.width/2,self.bounds.origin.y+self.bounds.size.height/2);
}

While we are on the topic of position views by their center, whenever you position a view such that its coordinates are not integers (as often occurs when using center), you risk running into issues with sub-pixel rendering. This causes your views to appear blurry (text is especially bad) or for lines to look somewhat off. To remedy this, we can use Objective-C's CGRectIntegral() function to lob of the fractionals from our coordinates. I use this a lot, so I made a short method for it.

//in .h file
//round frame coordinates to nearest integer
-(void) frameIntegral;

//in .m file
-(void) frameIntegral{
	self.frame = CGRectIntegral(self.frame);
}

Now whenever you change your frame in such a way that could potentially result in floating-point coordinates, just call this method right after to avoid any issues.

Alignment

We are now already able shave a lot of the superfluous code out of our script. However, we still haven't addressed the issue that positioning views relative to each other as part of a layout still requires doing a lot of simple arithmetic yourself. To address this, lets start by making a list of of the possible alignment positions we might want to use for easy reference. Lets use the nine standard positions.

//at the top of your .h file (outside the @interface)
typedef enum{
	PLKViewAlignmentTopLeft,
	PLKViewAlignmentTopCenter,
	PLKViewAlignmentTopRight,
	PLKViewAlignmentMiddleLeft,
	PLKViewAlignmentCenter,
	PLKViewAlignmentMiddleRight,
	PLKViewAlignmentBottomLeft,
	PLKViewAlignmentBottomCenter,
	PLKViewAlignmentBottomRight,
} PLKViewAlignment;

And now lets think of the ways we might want to use these:

//in .h file

//-------------------------
#pragma mark View Alignment
//-------------------------

//position the view relative to a point
-(void)align:(PLKViewAlignment)alignment relativeToPoint:(CGPoint)point;
//position the view relative to a rectangle
-(void)align:(PLKViewAlignment)alignment relativeToRect:(CGRect)rect;

The most obvious uses will be aligning relative to a point or within a rectangle (such as another view's frame). For the former, this would mean placing view such that its edge lines up with the point at the desired location. We are only change the origin of the view's frame (not the size), so we can use our helpers from above to keep it clean.

//in .m file

//-------------------------
#pragma mark View Alignment
//-------------------------

-(void)align:(PLKViewAlignment)alignment relativeToPoint:(CGPoint)point{
	switch (alignment) {
		case PLKViewAlignmentTopLeft:
			self.viewOrigin = CGPointMake(point.x, point.y);
			break;
		case PLKViewAlignmentTopCenter:
			self.viewOrigin = CGPointMake(point.x-self.viewWidth/2, point.y);
			break;
		case PLKViewAlignmentTopRight:
			self.viewOrigin = CGPointMake(point.x-self.viewWidth, point.y);
			break;
		case PLKViewAlignmentMiddleLeft:
			self.viewOrigin = CGPointMake(point.x, point.y-self.viewHeight/2);
			break;
		case PLKViewAlignmentCenter:
			self.center     = CGPointMake(point.x, point.y);
			break;
		case PLKViewAlignmentMiddleRight:
			self.viewOrigin = CGPointMake(point.x-self.viewWidth, point.y-self.viewHeight/2);
			break;
		case PLKViewAlignmentBottomLeft:
			self.viewOrigin = CGPointMake(point.x, point.y-self.viewHeight);
			break;
		case PLKViewAlignmentBottomCenter:
			self.viewOrigin = CGPointMake(point.x-self.viewWidth/2, point.y-self.viewHeight);
			break;
		case PLKViewAlignmentBottomRight:
			self.viewOrigin = CGPointMake(point.x-self.viewWidth, point.y-self.viewHeight);
			break;
		default:
			break;
	}

	//just to be safe
	[self integralFrame];
}

When dealing with rectangles, it isn't that much more complicated as you are effectively lining up the two points on both shapes (i.e. top left corner of view A and top left corner of view B). As such, we can reuse align:relativeToPoint:. We just need to determine which point on the frame we are interested in.

//in .m file

-(void)align:(PLKViewAlignment)alignment relativeToRect:(CGRect)rect{
	CGPoint point = CGPointZero;
	switch (alignment){
	case PLKViewAlignmentTopLeft:
		point = rect.origin;
		break;
	case PLKViewAlignmentTopCenter:
		point = CGPointMake(rect.origin.x+rect.size.width/2, rect.origin.y);
		break;
	case PLKViewAlignmentTopRight:
		point = CGPointMake(rect.origin.x+rect.size.width, rect.origin.y);
		break;
	case PLKViewAlignmentMiddleLeft:
		point = CGPointMake(rect.origin.x, rect.origin.y +rect.size.height/2);
		break;
	case PLKViewAlignmentCenter:
		point = CGPointMake(rect.origin.x+rect.size.width/2, rect.origin.y+rect.size.height/2);
		break;
	case PLKViewAlignmentMiddleRight:
		point = CGPointMake(rect.origin.x+rect.size.width, rect.origin.y+rect.size.height/2);
		break;
	case PLKViewAlignmentBottomLeft:
		point = CGPointMake(rect.origin.x, rect.origin.y+rect.size.height);
		break;
	case PLKViewAlignmentBottomCenter:
		point = CGPointMake(rect.origin.x+rect.size.width/2, rect.origin.y+rect.size.height);
		break;
	case PLKViewAlignmentBottomRight:
		point = CGPointMake(rect.origin.x+rect.size.width, rect.origin.y+rect.size.height);
		break;
	default:
		return;
	}
	[self align:alignment relativeToPoint:point];
}

Now we can achieve the code in the very first example of this post with only the following

[MyView align:PLKAlignmentTopRight relativeToRect:self.view.frame];

Much simpler and more much more legible than the oodles of code we had originally!

You can download the source files here.


Update November 2, 2017: Check out our case study for the Go Fit Yourself App.