Skip to content

Instantly share code, notes, and snippets.

@sebreh
Created September 25, 2019 06:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sebreh/8d3ae08f9808ee1495d91aa03a2814d1 to your computer and use it in GitHub Desktop.
Save sebreh/8d3ae08f9808ee1495d91aa03a2814d1 to your computer and use it in GitHub Desktop.
Structuring an iOS project

Structuring an ios project

As a software project grows, the name and location of a file becomes increasingly important. You want to be able to, based on the responsibility of a class, immediately know where to find it. An iOS project, like any other project, can grow quite large with time. If your app is also universal it immediately makes the code base significantly larger. In that case, you also want to be able to share as much code as possible across interfaces, but more on that later.

The fact is that beyond a certain point, a well structured project is essential for working efficiently with your code base.

A Note on View Controllers in a Universal App

I want to brifly mention how I structure my view controllers as it affects how I have chosen to organize my projects. When building a universal app, it’s easy to end up with giant view controllers littered with if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad). This happens a lot in Xcode’s auto-generated templates. There are a few drawbacks to this approach:

  • Keeping all code for both iPad and iPhone in the same file results in huge .m files that are harder to navigate and work with efficiently.
  • It is hard to easily distinguish what the code is supposed to do with all the added conditionals.
  • It is hard to get an instant overview of what code is used for a particular interface. Therefore, in large, I’ve gone the subclassing route. For example, I might have a view controller TasksViewController that displays a list of tasks in a UITableView. The base class will hold all the code shared across iPad and iPhone, typically related to relading data. I will then create two subclasses, TasksViewController_iPhone and TasksViewController_iPad to handle any interface specific stuff.

There are also drawbacks to this approach; Often I need to write some glue code to define the interface between the base class and the subclasses to allow them to interact. Typically this includes callbacks to the subclasses for state changes, and for the subclasses to trigger some action in the base class. However, I end up with smaller implementation files and it becomes trivial to know which piece of code is shared and what is exclusive to a certain interface. It is also very easy to filter out these files in the Xcode navigator while working with them. To me, these benefits outweighs the drawbacks.

Subclassing might not always be the best way, especially for trivial classes, and I am not religous about it. But for view controllers, app delegates and any other significant pieces of code I have found this approach quite useful.

My Structure

Apple provides little guidance on how to structure larger iOS projects. Looking at the generated template projects in Xcode, it pretty much dumps all files, app delegate and view controllers, into a single root group. Contrast this with something like Rails which generates a set of subdirectories, each with a clear responsibility.

A couple of months ago, after finishing the Podio iPad app, I took a stab at improving the structure of the Xcode project. This is the what I came up with:

/<ProjectName>
    /Shared
        /Application      # App delegate and related files
        /Controllers      # Base view controllers
        /Models           # Models, Core Data schema etc
        /Views            # Shared views
        /Library          # Anything that falls outside of the MVC pattern
        /Support          # Categories and helpers
    /iPhone
        ...               # Same structure as 'Shared' but with interface specific classes
    /iPad
        ...
    /Other sources        # Prefix headers, main.m
    /Supporting files     # Info.plist
/Resources                # Images, videos, .strings files
/Vendor                   # 3rd party dependencies not managed by CocoaPods

The structure on disk is the same, with some additional directories:

  • Scripts: All project-related scripts, typically executed as rake tasks using a Rakefile in the project root directory.
  • Translations: Holds all the base strings and localized gettext files used by our translation tool.
  • Pods: Folder containing all dependency CocoaPods. Auto-generated when running pod install. This structure has worked well for me so far, but any feedback is welcome. It would be nice to have some kind of community best practices around how to structure an iOS project. Not only to make code easier to manage, but also to make is easier to move between projects.

Jan 15th, 2013 Development, iOS

Copyright © 2013 Sebastian Rehnby

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment