Posts in uikit

As previously mentioned: to get the UI to update, you need to run your
UIKit configuring code on the main thread. Peter Stienberger has posted agreat snippet of code that raises an assertion whenever you attempt to
access UIKit code from off of the main thread. Simply add the file to your
project (and swap out the PSPDFLogError with an NSLog) and build and run.
Everytime you call UIKit code off of the main thread, it'll crash your app.
Great for finding bugs.

In OS X Lion and iOS 6 Apple added a new way to layout views, Auto
Layout. This is a very powerful system that will handle a lot of
the work and overhead of arranging your views. A well defined layout can make
many headaches disapear entirely. However, it is a bit…quirky…to say the
least.[1]

Throughout this post, we'll be discussing code from a sample project I've
created, called AutoLayoutAlignment, available in github.

What Options Do

In the constraintsWithVisualFormat:options:metrics:views:, the options
parameter is a bitmask that allows you define how the views in the format
string are aligned with each other. For example, the string@"V:[first][second][third]", only tells you that the three views should be
vertically stacked. It does not say what to do if the views are of different
widths.

You could handle this by putting in a horizontal set of constraints for each
view, but this would become quickly tedious. Instead you can pass in an option
to tell the layout engine how to poistion them relative to each other.

The Options

There are three sets of options: ones that apply to vertical constraints, ones
that apply to horizontal constraints and ones that adjust the direction
horizontal constraints apply. They are all part of NSLayoutFormatOptions

Vertical Constraint Options

NSLayoutFormatAlignAllLeft - This aligns all of the views on their left edge.

NSLayoutFormatAlignAllRight - This aligns all of the views on their right edge.

NSLayoutFormatAlignAllLeading - This aligns all of the views on the edge that is the start of text in the current locale (English: left, Hebrew: right).

NSLayoutFormatAlignAllTrailing - This aligns all of the views on the edge that is the end of text in the current locale (English: right, Hebrew: left).

NSLayoutFormatAlignAllCenterX - This aligns all of the views by setting their center's X value equal to each other.

Of particular note is the leading and trailing alignments. Generally speaking
you probably want to use these instead of left and right, to allow your UI to
adjust for languages that read in the opposite direction than yours.

Horizontal Constraint Options

NSLayoutFormatAlignAllTop - This aligns all of the views on their top edge.

NSLayoutFormatAlignAllBottom - This aligns all of the views on their bottom edge.

NSLayoutFormatAlignAllCenterY - This aligns all of the views by settings their center's Y value equal to each other.

NSLayoutFormatAlignAllBaseline - This lines up the views according to their baseline, which for text based views is the bottom of text that does not drop down (like g, p, j, etc). For non-text views it is the same as the bottom edge.

When lining up text with each other it tends to look visually appealing to
align on the baseline, but may not be what you want with a mixed set of views.

Direction Constraint Options

These can be or'd (|) into another option you pick for horizontal constraints.

NSLayoutFormatDirectionLeadingToTrailing - The format string is read in assuming that the leading view in the string should be on the leading side of the display. Once again, based on the locale in use.

NSLayoutFormatDirectionLeftToRight - The format string is read in assuming that the leading view in the string should be on the left side of the display.

NSLayoutFormatDirectionRightToLeft - The format string is read in assuming that the leading view in the string should be on the right side of the display.

The default is NSLayoutFormatDirectionLeadingToTrailing and is generally what
you want to use.

How They Apply

Go ahead and launch the example app, and you'll quickly see how these alignment
options work.

At the bottom center are the visual format strings being used in the two large
views on screen. The alignment settings are defined in the popover presented
from the bottom left button. Try adjusting the settings for the alignment
options, you should notice the text labels moving around their parent views,
and hopefully see just how these work.

It is important to note how the views cease to move around if you disable the
superview connecting constraint. Even though the superview is reference in the
format string as |, the reference is only used for positioning purposes, and
alignment options do not apply. If you do not set up the alignment to the
superview, the layout is considered ambiguous and the layout engine can't
perfectly apply it. We'll discuss later what ambiguity is, and how to fix it.
For now, take note that there is a button that will log to the console the
trace that will show what views on screen are ambiguous.

Conclusion

Hopefully you now understand what the options argument is for, and how you
can use it to align views when defining them in the visual format string.
Please send questions my way, either via email (spr (at) iosdevelopmentjournal
(dot) com) or on twitter/app.net at _spr_.

The Problem

So Apple recommends that we avoid doing too much work on
the main thread. This is great advice, the less time you spend wasting CPU
cycles in the main thread, the more responsive your UI will be. In my opinion a
well defined iOS application will avoid doing more than update the UI on the
main thread.

One prime example I've run into was some code that did a synchronous network
request. It waited for the network response before returning and someone
thought it had to run on the main thread. This resulted in a lock-up during
some animations I was working on.

There's a number of topics[1] that I plan to discuss about getting things
off of the main thread, but today I'm going to discuss running things on the
main thread.

If you've set up your app to do all of the heavy lifting in some secondary
thread or in a dispatch queue, you will probably need to update you
UI based on this work. The first thing you're likely to do is simply update the
UIView object:

The next time the UI code checks to see if the UILabel has changed, it will see
that, yes it has, and upate the display. Sadly, when this happens is often
still fairly late.

The Solution

To really get things updated, setNeedsDisplay needs to be called from the
main thread, where the UI does its work. If you can ensure that your code runs
there, it should update with no noticable delay. Thankfully, Apple gave us a
wonderful tool for executing small bits of code anywhere on a specific thread
or queue.

Suddenly your label updates the instant your code runs. The best part is it can
be put in anywhere and since it runs on the main thread, the UI will update
almost immediately.

So when you need to get some code to run on the main thread, usually to get
your UI to update with new information, you just use dispatch_async anddispatch_get_main_queue(). Now go forth, and write responsive UIs!

These include handling network calls, generally working with Grand Central Dispatch, and some common pitfalls with blocks. Look for them soon. ↩︎