Skip to content
Tyler Fox edited this page Aug 31, 2015 · 22 revisions

Getting started with PureLayout

If you haven't checked it out already, start with the demos in the Xcode project in this repository. The examples for iOS and OS X covers all sorts of scenarios, from beginning to advanced usage of PureLayout and Auto Layout in general. Even if you feel comfortable with PureLayout, you'll probably learn something new by looking through these demos. Be sure to read through the comments and code in the .m file for each demo as you run the project, and play with the existing code to try new things and make sure you understand what's going on.

Where to add constraints in code

If you're adding constraints from within a UIView subclass, you should override the -[UIView updateConstraints] method. If you're adding constraints from within a UIViewController subclass, you override the -[UIViewController updateViewConstraints] method. You must call super from both, and you should call super at the very end of your implementation. (You may get a runtime crash if you call super before you change constraints on the view.)

Note that both updateConstraints methods may be called more than once during the lifetime of the object (and frequently are called many times), so you need to avoid creating & adding duplicate constraints -- duplicate constraints will degrade performance and potentially cause other issues. You should keep a BOOL flag that lets you know once you have done your initial constraint setup. Here's an example of a typical implementation:

// In the class header or class extension:
@property (nonatomic, assign) BOOL didSetupConstraints;

// ...

// In the class implementation:
- (void)updateConstraints {
    if (!self.didSetupConstraints) {
        // Do your initial constraint setup
        // ...
        self.didSetupConstraints = YES;
    }
    [super updateConstraints];
}

Batch-creating Constraints

By default, when you call a PureLayout API that creates a constraint, PureLayout automatically activates (installs) that constraint for you. This is probably the behavior you want 95%+ of the time, which is why it's the default.

If you want to create a constraint but prevent it from being automatically activated, you should use the PureLayout API:

+[NSLayoutConstraint autoCreateConstraintsWithoutInstalling:]

You call this class method and pass a single block containing any code you want. The only thing different that will happen when the code within the block executes is that any constraints created by PureLayout will not be automatically activated; instead, when the block finishes executing, this method will return an array of all the constraints PureLayout created (but did not install) within the block. So you can easily batch-create a handful of related constraints, which you then store to use later. Since the constraints aren't automatically activated, it is programmer error to create constraints this way but fail to store them to activate later on!

Now, that brings us to the following API:

+[NSLayoutConstraint autoCreateAndInstallConstraints:]

At first glance, it may not be immediately clear why this API exists, since PureLayout automatically installs constraints by default. Here's why: when you place calls to PureLayout inside a block passed to the above API, there are two things that happen:

  1. The PureLayout constraints created inside of the block are all collected together into a single array and returned to you. (This is extremely convenient if you need a reference to multiple related constraints to store for later removal, etc.)
  2. All of the PureLayout constraints created inside of the block are activated simultaneously at the very end, in one large batch. This is often more efficient than activating each constraint one by one.

Pro tip: you can even nest calls to the above APIs!

Using PureLayout together with Interface Builder constraints

You may want to use a combination of an Interface Builder file (nib/xib/storyboard) that specifies some constraints along with additional constraints added in code using the PureLayout API. In general, this is a fine way of doing things.

Be aware that when using Xcode 5, you are allowed to have ambiguous layouts in Interface Builder, and at build time (without telling you) Xcode will automatically create and add in the necessary constraints to make your layout fully specified. This can cause problems for you at runtime if these auto-generated IB constraints end up conflicting with constraints you create and add in code.

To solve this issue, you'll need to create placeholder constraints for any ambiguous parts of your layout in Interface Builder. These placeholder constraints are removed from your layout at build time, and also prevent the auto-generated IB constraints from being added in their place. See this Stack Overflow answer for more info.

Debugging constraint issues

If you're having an issue with a constraint being broken due to a conflict (check your console output), one of the best ways to debug is to comment out constraints one-by-one in reverse order until the issue disappears. (Alternatively, you can comment all the constraints out and add them back in one-by-one until the issue appears.) This will help you isolate the particular constraint(s) that are causing the problem.

Don't forget to use the identifier property of constraints to set a human-readable description string. This can help greatly when you have a bunch of constraints in conflict, and you can quickly figure out which ones are which. See the iOS Demo 8 (Objective-C, Swift) in the PureLayout Example project to see how these work.

Using Auto Layout in table views

Using Auto Layout within a UITableViewCell can be very powerful, but also very tricky to get right (and not have atrocious performance). I've written a nice post about this over at Stack Overflow which includes a high-level overview of the approach and some tips to get you started.

Learning more about Auto Layout

Check out the awesome Advanced Auto Layout Toolbox article over at objc.io by Florian Kugler. I promise it's worth the read.