Posts in uikit

  • Verifying UIKit is Running on the Main Thread

    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 a
    great 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.

  • Alignment Options in Auto Layout

    In OS X Lion and iOS 6 Apple added a new way to layout views, Auto
    . 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

    I recommend that you read the guide to the visual format language before going on.

    This post will discuss the various options that you can set in
    constraintsWithVisualFormat:options:metrics:views:. These options affect
    how the views described in the format string are to be aligned with each other.

    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

    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.

    There is an additional setting in the app that is not an
    NSLayoutFormatOptions item. The "Apply Option to Superview as Well" setting
    adds an additional constraint to these views. It applies a constraint that
    connects the top or leading view to the superview using the equivalent
    NSLayoutAttribute by using

    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.


    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/ at _spr_.

    Keep an eye out for future auto layout posts that will cover issues like
    multi-line labels, creating sufficient layouts, and handling dynamic view

    1. I will not be tackling interface builder's use of auto layout. I do not use interface builder heavily, and its quirks are a whole different story. ↩︎

  • Forcing Things to Run on the Main Thread

    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:

    {% highlight objc %}
    someUILabel.text = updatedString;
    {% endhighlight %}

    Well, it turns out that doesn't really do anything. You might get really lucky
    and see the label update seconds or minutes later. The first thing to do is by
    adding a call to setNeedsDisplay.

    {% highlight objc %}
    someUILabel.text = updatedString;
    [someUILabel setNeedsDisplay];
    {% endhighlight %}

    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.

    {% highlight objc %}
    dispatch_async(dispatch_get_main_queue(), ^{
    someUILabel.text = updatedString;
    [someUILabel setNeedsDisplay];
    {% endhighlight %}

    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 and
    dispatch_get_main_queue(). Now go forth, and write responsive UIs!

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