Keeping ViewController files small

If you’re working on a complex iOS app, it’s very easy to create a UIViewController subclass with a huge amount of code. One of the many code guidelines I learned at Google was the simple idea of keeping functions and files small. For example, I would recommend trying to keep the vast majority of your functions around 40 lines or less, and trying to keep all of your files under 1000 lines. This post presents a technique that can help you achieve smaller file size.

Why small source files are good

Here are two principles to code by:

  1. Your code should be simple to users, and
  2. Everyone, including you, is a user.

I could write a whole post about these ideas, but let me just summarize by saying that anyone working on your codebase, including future you, cares a lot about how simple things are. When each individual idea in your codebase is succinct and transparent, things are easy to modify and update, and bugs are harder to create and easier to squash.

File size is not a perfect predictor for code simplicity, but it’s a darn good heuristic.

Use categories on your own classes

Instead of having one header and one implementation (h,m) file for your UIViewController subclass, I suggest splitting the main pieces of functionality out into their own files, as categories of your class.

For example, suppose we’re writing a tetris clone for the iPad. (Don’t actually do that, btw. You might get sued.) Let’s have a primary view controller called TetrisViewController. It would be easy for this file to become huge, so we can split different aspects of gameplay into separate pieces, such as this:

  • TetrisViewController.{h,m}
  • TetrisViewController+Tutorial.{h,m}
  • TetrisViewController+Animations.{h,m}
  • TetrisViewController+Network.{h,m}

Since the class is officially declared in TetrisViewController.h, this is where all the instance variables are declared. Any code specific to tutorials, animations, or network play goes in its respective category file. The goal is to partially encapsulate that functionality in its own file, while logically speaking, those methods will have full access to all the variables of the class. A good rule of thumb is to group methods together when you are likely to be editing them together; you want to minimize the need for file-switching while programming.

Template code

Let me fill in the details of how these files might actually look.

// TetrisViewController+Animations.h

#import "TetrisViewController.h"

@interface TetrisViewController (Animations)

// Public method names start with the category name.
- (void)animationsOnCompletionOfRows:(NSArray *)rows;
- (void)animationsOnLevelDone;

// TetrisViewController+Animations.m

#import "TetrisViewController+Animations.h"

// Declare any private methods.
@interface TetrisViewController (AnimationsPrivate)

- (void)animationsForSingleRow:(int)rowIndex;


@implementation TetrisViewController (Animations)

- (void)animationsOnCompletionOfRows:(NSArray *)rows {
  for (NSNumber *rowNumber in rows) {
    [self animationsForSingleRow:[rowNumber intValue]];

- (void)animationsOnLevelDone {
  // Execute level done animation.

#pragma mark private methods

- (void)animationsForSingleRow:(int)rowIndex {
  // Execute single-row animation.


Within the category implementation, you’re free to call any public method on the original view controller, and any methods (including category-private ones) within the category. Note that you can’t call private methods of the original class from the category, at least not without a compiler warning. In practice, I’ve found that this is not a problem. If the categories are separate enough ideas, the methods you need to call from a category will most often naturally be public methods. In some cases where this was not true, I found it made sense to make a previously-private method public to solve this. The small number of times when I did this have all made sense in retrospect, in the sense that the newly-public methods did not break encapsulation.

The header file of the original class doesn’t need to know anything about the category files. The implementation file needs to import them so you can call them. I find it useful to think of these as sort of hooks into the original class. Ideally, you only add about one line of code to the original class per public category method. In other words, you want your code impact on your main m file to be very small when you add a category like this.

Here’s an example of how your main implementation might look:

// TetrisViewController.m

// Import the main header first, to be sensitive to any uncaught dependencies in the header.
#import "TetrisViewController.h"

// Import the category headers next, again trying to catch any header dependencies.
#import "TetrisViewController+Animations.h"
#import "TetrisViewController+Network.h"
#import "TetrisViewController+Tutorial.h"

// Import other headers, declare private methods, etc.

// Then methods, which might include something like this:
- (void)someRowsCompleted {
  NSArray *rowsDone = [self getRowsDone];
  [self incrementScoreBasedOnRows:rowsDone];
  [self animationsOnCompletionOfRows:rowsDone];

One last thing: it’s definitely more work to retroactively pull out categories from a huge view controller, so I highly recommend trying to split out categories as you code, as opposed to after you’ve got huge files. I hope that’s helpful!