Achieving Zen With Auto Layout (2nd Edition)

Last year I released a book based on all my speaking engagements around Auto Layout called Achieving Zen With Auto Layout. The book was very well received when it was announced and it made me realize I enjoyed writing about technical topics again (with the absence of a publisher, everything is wonderful!).

I’m pleased to announce that I’ve spent the last few months updating the book for a second edition. This new edition of the book contains a ton of new content and converted nearly every piece of code from Objective-C to Swift.

New topics covered include:

If you’re new to iOS and Auto Layout or just want to learn about what’s new with layout in iOS 9 and El Capitan, this is the book for you.

Purchase Achieving Zen With Auto Layout.

Read more about. . .

Auto Layout Debugging In Swift

I’ve been working with Swift primarily over the last month. Recently I started working on a new custom interface piece that was having some rendering issues with its layout constraints. I went into LLDB and quickly realized that using private methods such as _autolayoutTrace and recursiveDescription to print out a hierarchy of my views and see ambiguity wasn’t possible out of the box.

The reason for this is that when you’re in a Swift frame, LLDB is expecting you to call a Swift method it knows about. Since _autolayoutTrace and the like are private API, they don’t have any visibility to Swift. Safety!

There are a few different ways to get around this. The first is straight in LLDB. You can use the expr command to tell LLDB that you are passing it a snippet of Objective-C code like so:

<code class="bash">expr -l objc++ -o -- [[UIWindow keyWindow] _autolayoutTrace]  

What we’re doing here is printing out our entire view hierarchy to the debugger. Frequently typing that long of a statement is obviously a bit tedious, so I tend to put it in my .lldbinit file.

<code class="bash">command alias alt expr -l objc++ -O --[[UIWindow keyWindow] _autolayoutTrace]  

Now you can just type alt and get the same output from the debugger.

You’ll notice that I am throwing this out for the entire contents of the keyWindow. I haven’t been able to find a way to pinpoint it down a single property such as self.view, so if you have any feedback on that, please share!

If you’re mixing Objective-C and Swift, you likely already have a bridging header. You can bridge add a category on UIView that exposes the recursiveDescription and _autolayoutTrace methods to Swift.

<code class="objectivec">#ifdef DEBUG

@interface UIView (LayoutDebugging)

#pragma clang push

#pragma clang diagnostic ignored “-Wincomplete-implementation”

- (id)recursiveDescription;

- (id)_autolayoutTrace;

#pragma clang pop

@end

#endif

And the implementation file.

#import “UIView+LayoutDebugging.h”

#ifdef DEBUG

@implementation UIView (LayoutDebugging)

// Nothing to see here!

@end

#endif

Let’s walk through this. You’ll notice that I have the entire thing wrapped in an #ifdef DEBUG statement because I am working with private APIs that I presume the App Store usage checker would flag and reject your app against. With the #ifdef, I am saying that it should only be included on development builds. Apple will have no idea what abuses we are committing since it will never make it to the release builds!

The other atrocity I am committing in this file is the use of #pragma clang diagnostic to tell the compiler to ignore any ‘uninmplemented method’ warnings that will pop-up from not being able to find an implementation for the two methods we defined in our category. Since they exist as private API, we don’t need to reimplement them.

Now if you break in a Swift frame with LLDB and try to call self.view._autolayoutTrace() you’ll get an output you expected.

Happy debugging!

If you’ve found this post useful, and want to learn more about how to best take advantage of Auto Layout in your OS X and iOS apps, be sure to purchase my new book Achieving Zen With Auto Layout

Read more about. . .

Auto Layout In iOS 8 - layoutDebuggingIdentifier

Another new identifier Apple added in iOS 8 is the private API property _layoutDebuggingIdentifier to UIView that you can use to clean up what is output in _autolayoutTrace. Since it is private API, you don’t want to ship with this code in because Apple will likely reject it, but for debugging purposes it can be mostly harmless. Mostly.

There’s no easy way to set the _layoutDebuggingIdentifier identifier in a Storyboard or Xib, so we will have to add a bit of code to take advantage of it.

To take advantage of this:

  1. Open one of your view controllers.
  2. Override - (void)viewDidLoad if you haven’t already.

There’s a few different spots you could likely define the _layoutDebuggingIdentifier, but for view controllers, I tend to just put them in viewDidLoad. Here’s a sample of the code I use:

#ifdef DEBUG
    SEL selectorName = NSSelectorFromString(@"_setLayoutDebuggingIdentifier:");
    NSString *identifier = @"Email Label";
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [self.emailLabel performSelector:selectorName withObject:identifier];
#pragma clang diagnostic pop
#endif

Oh boy. This looks crazy. Let’s break down what’s going on line-by-line.

On the first and last lines, I’m again wrapping everything in an #ifdef DEBUG block because I don’t want to ship this bit of code with my product to the App Store.

The second line I am creating a SEL variable by calling the NSSelectorFromString function and passing in “_setLayoutDebuggingIdentifier:” as a string. The line below it is defining what I want the _layoutDebuggingIdentifier string to actually be.

From there, things start to get weird. I’ve got three different #pragma calls. The first one is saying that I am going to start adding some specific instructions for the compiler about things I want it to take into account in the following set of code. That’s what “push” is. The last #pragma says “pop”, which means I am done passing those bits of code specific diagnostics in.

The specific diagnostic message I am calling is #pragma clang diagnostic ignored "-Warc-performSelector-leaks" which is telling the compiler to ignore the warning about my performSelector call possibly leaking, because it may not exist. Since _layoutDebuggingIdentifier is private API, the public framework headers don’t know what to do with it, so the compiler assumes it doesn’t exists. I assure you it exists as of iOS 8 though, so we can safely ignore that warning.

The one caveat of course is that since this is private API, Apple can either remove it or change it in a future release. Be aware.

Thus far we’ve set a single _layoutDebuggingIdentifier for our email label. Go ahead and set them for the rest of the controls that you care to have nicer output from.

After you do that, run the application again and print out the output of _autolayoutTrace.

(lldb) po [self.view _autolayoutTrace]
UIWindow:0x7fdb8511de90  
|   •UIView:0x7fdb83d3d470
|   |   *Email Label:0x7fdb83d3d780
|   |   *Password Label:0x7fdb83d3fae0'Password'
|   |   *Logo Image:0x7fdb83d3ff70
|   |   *Email Field:0x7fdb83d40980
|   |   |   _UITextFieldRoundedRectBackgroundViewNeue:0x7fdb83d4a240
|   |   *SignIn Button:0x7fdb83d4cfe0'Sign-In'
|   |   *Password Field:0x7fdb83d4e070
|   |   |   _UITextFieldRoundedRectBackgroundViewNeue:0x7fdb83d4f4b0
|   |   *_UILayoutGuide:0x7fdb83d4f9a0
|   |   *_UILayoutGuide:0x7fdb83d503b0

Ah…much nicer.

If you’ve found this post useful, and want to learn more about how to best take advantage of Auto Layout in your OS X and iOS apps, be sure to purchase my new book Achieving Zen With Auto Layout.

Read more about. . .

Auto Layout In iOS 8 - Layout Margins

Apple has added a few additions to both iOS 8 and OS X Yosemite that make working with Auto Layout even more of a no brainer than before. Over the next few weeks, I am going to take some time to write about each one of them to give fellow developers an idea of how to make use of these features in their products.

Up first is layout margins.

In iOS 8, Apple added the layoutMargins property on UIView. layoutMargins takes a UIEdgeInsets value that lets you explicitly define the whitespace that your views can use to guide where portions of the interface should be placed.

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];  
label.translatesAutoresizingMaskIntoConstraints = NO;  
label.layoutMargins = UIEdgeInsetsMake(-20, -20, -20, -20);  

For anyone that has used the topLayoutGuide or bottomLayoutGuide properties on UIViewController in iOS 7, laying out along a margin shouldn’t be a foreign concept. Those predefined values made it so that the content of your view wouldn’t be sunk underneath a transparent tab or navigation bar. With iOS 8, Apple has extended that functionality so that you can apply custom margins to any UIView that you work with.

To go with the new layout margins functionality, there are new attributes added exclusively for iOS 8 for establishing relationships with Auto Layout.

If these all look familiar, they should. They are pretty much equivalent to the old attributes you used such as NSLayoutAttributeLeft, NSLayoutAttributeRight, and NSLayoutAttributeCenterY. The only difference is that these new methods take into account the layoutMargin values that you set.

If you are targeting iOS 8, you should start adopting these new margin capabilities in your app, because it will lead to much cleaner code. Instead of having to use the constant value of your Auto Layout equation to insert padding, you can now just set the layoutMargins value specifically on the view, and let Auto Layout use those margins as part of its process.

If you’ve found this post useful, and want to learn more about how to best take advantage of Auto Layout in your OS X and iOS apps, be sure to purchase my new book Achieving Zen With Auto Layout

Read more about. . .

Achieving Zen With Auto Layout - The Book

tl;dr I am writing a book on Auto Layout. You can purchase it now.

Over the last year I have been criss-crossing the country giving a talk called Achieving Zen With Auto Layout to any conference or user group that would host me. Speaking is not my primary goal. I am not an ex-developer. I just enjoy doing it a few times a year, especially since I spend so much time sitting in front of a computer in a solitary room typing. Even the most antisocial developers need a bit of human interaction.

The talk has been well received far beyond my expectations. Everywhere I have presented has given it high marks and attributed it with helping them get over the hurdles of learning and using Auto Layout in their jobs.

I have had it in the back of my head that I wanted to turn the talk into a book for a while. Every time I have thought about it, however, I have pushed the thought away. Writing a book is hard. Dealing with publishers is a pain. You don’t make much money doing it. Why bother?

Despite all the reasons to not do the book, I kept coming back to the main reason I wanted to do it: I like helping people. I like when people tell me my talk has helped them learn a new technology. I enjoy having people say they learn new things from CocoaRadio.

So, I started writing. Not full-time. Not even part-time. I just started writing when I had time. Over the last few months, I have amassed enough content to generate what I consider to be the first 1/3 of the book.

Achieving Zen With Auto Layout is the eBook companion to my talk of the same name, but with the goal of being much more expanded than what I am able to do in a 45-60 minute on-stage presentation.

This is a beta book right now. There are no screenshots (iOS 8 does still have a tiny bit of NDA that prevents those), copy editing hasn’t been done, and I still need to hire an illustrator to do a cover and some other things in the book for me. Content-wise though, I’m proud of what is there so far, and I’m excited to finish the rest of the book in time for the iOS 8 launch later this fall.

You can purchase Achieving Zen With Auto Layout today and get access to a PDF of the current state of the book, as well as a private GitHub repository where I am writing and storing all the sample code as I go. So far this has proven to be a wonderful way to write, because buyers of the book are able to provide direct feedback to me about the book so I can iron out any confusion or missing things I may not have thought of during my first draft.

If you’ve struggled with Auto Layout in the past, I truly believe Achieving Zen With Auto Layout can help you get over those hurdles.

Purchase “Achieving Zen With Auto Layout”

Read more about. . .