scottr.org

  • Home
  • About
  • Asynchronous Networking with NSURLSession

    iOS 7 introduces an entire new networking stack for developers,
    NSURLSession. Generally it makes the common tasks simple, and the hard
    tasks possible. It also drives the new background fetch capabilities as well.

    Like my earlier post, offloading your networking from the main
    thread is a simple way to help keep an app responsive. Doing this with
    NSURLSession is actually quite easy.

    NSURL *url = [NSURL urlWithString:@"http://iosdevelopmentjournal.com"];
    NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
                                                         completionHandler:
                              ^(NSData *data, NSURLResponse *response, NSError *error) {
        if (data) {
            // Do stuff with the data
        } else {
            NSLog(@"Failed to fetch %@: %@", url, error);
        }
    }];
    [task resume];
    

    This will run the networking off of the main thread, and the callback will come from a system network queue. Generally this is what we want. If you want to have control over what queue the callback comes from, or to be able to handle authentication requests, you should create your own NSURLSession and delegate.

    _spr_

    September 18, 2013
    Posts
    networking, nsurlsession
  • 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.

    _spr_

    June 1, 2013
    Posts
    gcd, uikit
  • Alignment Options in Auto Layout

    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]

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

    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
    [constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:].

    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_.

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

    [^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.

    _spr_

    April 22, 2013
    Posts
    auto-layout, uikit
  • Swipe to Delete with Multiple Selection

    The Problem:

    (Solution found via StackOverflow)

    You have a UITableView that has
    allowsMultipleSelectionDuringEditing set to YES, since you’d like to
    allows for bulk deletes or other actions. Prior to adding bulk editing support
    you also could perform a swipe-to-delete when not in editing mode. However,
    you’ve just noticed that swipe-to-delete no longer works. And you want both.

    The Solution:

    So it turns out that you can’t have allowsMultipleSelectionDuringEditing
    active and have swipe-to-delete work at the same time. So what you need to do
    is only enable allowsMultipleSelectionDuringEditing when the table view is in
    editing mode.

    This is achieved by a simple addition to your UITableViewController
    sub-class.

    - (void)setEditing:(BOOL)editing animated:(BOOL)animated {
        [super setEditing:editing animated:animated];
        self.tableView.allowsMultipleSelectionDuringEditing = editing;
    }

    And with that swipe-to-delete works, and so does bulk editing!

    _spr_

    April 22, 2013
    Posts
    uitableview
  • Don’t Reference View Controller Views in init

    This is more of a note to my future self:

    Don’t reference a view controller’s view in an init method.

    Why not? Well, let me tell you what I did.

    The Setup

    Custom UITableViewController subclass. Has a few custom variables that
    store useful data. An array of things to display, some basic text, etc. These
    all get set in a custom init method: initWithTitle:Items:. All very simple.
    These variables then get used in viewDidLoad to setup the table view, etc.

    The Problem

    [self.tableview registerClass:[UITableViewCell class] forCellReuseIdentifier:@"CELLID"]

    Running that in my init function results in viewDidLoad running before I had
    set up the other variables. Which meant viewDidLoad was running before any of
    its variables were initialized correctly. Needless to say, this resulted in
    some strange behavior.

    The Solution

    Stop referencing the view in the init method.

    _spr_

    March 21, 2013
    Posts
    mistakes, uiviewcontroller
  • MPMoviePlayerController Going Fullscreen Creates A Blackout

    The Problem:

    (Solution found via StackOverflow)

    You’ve added an MPMoviePlayerController to one of your view controller’s
    child views. You hit play, it starts playing the video. Then you hit the
    fullscreen button. It fills the screen, and suddenly everything goes black, you
    can’t get any controls, and all that happens is the audio keeps playing.

    So what went wrong?

    What Happened

    So my best guess is that the view that contains the MPMoviePlayerController
    view is a temporary one in your view controller. Something that you get rid of
    when the view controller’s view stops being displayed. So what you decided was
    to remove the view from the view controller (removeFromSuperview) when the
    view controller is no long displayed.

    The obvious place to do that is in viewWillDisappear:, right? It
    consolidates all these actions into one place, and happens automatically.

    The problem? When the movie goes fullscreen, your view disappears and
    viewWillDisappear: is called.[^1] MPMovePlayerController doesn’t work well
    when its view gets removed from the view hierarchy. Whoops.

    The Solution

    I solved this by moving my view destroying code into a new method and out of
    viewWillDisappear:. In my case all the times I wanted the view to be removed
    are times when I’m triggering viewWillDisappear: manually with a call to
    pushViewController:animated: to the navigationController. So right
    above that call, I added a call to my new method.

    If you have situations where you don’t control the transition that causes your
    view to be destroyed, you might want to add a BOOL to safegaurd the view from
    being destroyed if video playback is happening.

    [^1]: You might run into this problem transitioning from iOS 5 to iOS 6. Apple fixed a bug where viewWillDisappear: wasn’t being called for the fullscreen transition. So this doesn’t happen in iOS 5, but does in iOS 6.

    _spr_

    March 16, 2013
    Posts
    media, uiviewcontroller
Previous Page
1 2 3
Mastodon

Proudly Powered by WordPress

    • Follow Following
      • scottr.org
      • Already have a WordPress.com account? Log in now.
      • scottr.org
      • Edit Site
      • Follow Following
      • Sign up
      • Log in
      • Report this content
      • View site in Reader
      • Manage subscriptions
      • Collapse this bar