Tag Archives: UIViewController

How to write a Custom Initialiser in Swift

I’m used to initialising my Objective-C objects with a custom initialiser. It’s a trick I’ve learnt from the legendary Simon Allardice back in the day. It works a treat every time!

Turns out it’s a Cocoa and Cocoa Touch design pattern, and the principle can be applied similarly in Swift, with a couple of important differences.

Or shall I say pitfalls?

Continue reading

How to test if a Navigation Controller’s Back Button was pressed

Screen Shot 2015-11-10 at 11.33.31

Sometimes it’s helpful to know if the Back Button on a UINavigationController was pressed. For example, an app that has a Save button on the left could double-up the Back Button as a way to cancel the operation.

Since iOS 5 there’s a view controller property that we can check in viewWillDisappear: if isMovingFromParentViewController returns YES, the current view controller is about to be popped off the stack.

Call the following method in the view controller that’s currently on the navigation stack, and being presented by the navigation controller:

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    // check if the back button was pressed
    if (self.isMovingFromParentViewController) {

        // do something here if that's the case
        NSLog(@"Back button was pressed.");

viewWillDisappear is called whenever our view controller is about to be dismissed, either by the navigation controller, or modally. We may not want anything to happen when the dismissal happens while this view controller was presented modally, so this check makes sure we only opt-in to the navigation controller’s Back Button presses.

Note that the property is only available inside the viewWillAppear and viewWillDisappear methods.

3D Touch in iOS 9, Part 1: Peek and Pop

Screen Shot 2015-09-26 at 09.48.21

With the introduction of the iPhone 6s we have some new ways of getting user input via 3D Touch. Now THAT’S innovative!

There are several things we can do with 3D Touch, and the first one we’ll explore here is Peek and Pop. When the user presses down a little harder, a Peek (or preview) appears, and if the user presses even harder, a Pop (or commit) view controller appears. Both are plain view controllers that are called via a delegate method we need to implement. Let’s see how this works.

Before we begin

The first thing we’ll need to do is to indicate that our view controller will conform to a new protocol. It’s called the UIViewControllerPreviewDelegate Protocol.

@interface ViewController () <UIViewControllerPreviewingDelegate>
@property (nonatomic, strong) UILongPressGestureRecognizer *longPress;

For backward compatibility I’ll also add a long press gesture recogniser here. Should our sample app be run on a device without 3D Touch support, at least the preview can be brought up via a long press gesture.

We’ll check if 3D Touch is available using something like the following method. To complete the setup, I’ve also included a custom initialiser for the long press gesture.

- (void)check3DTouch {
    // register for 3D Touch (if available)
    if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
        [self registerForPreviewingWithDelegate:(id)self sourceView:self.view];
        NSLog(@"3D Touch is available! Hurra!");
        // no need for our alternative anymore
        self.longPress.enabled = NO;
    } else {
        NSLog(@"3D Touch is not available on this device. Sniff!");
        // handle a 3D Touch alternative (long gesture recognizer)
        self.longPress.enabled = YES;

- (UILongPressGestureRecognizer *)longPress {
    if (!_longPress) {
        _longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(showPeek)];
        [self.view addGestureRecognizer:_longPress];
    return _longPress;

The above checks a new property of the UITraitCollection class called forceTouchCapability. If it returns the enum “available”, then the device is 3D Touch capable and it’s switched on. Note that at the time of writing, only the iPhone 6s and 6s Plus support this feature, and of course the iPad Pro when it arrives in November. Neither the iPhone 6 or earlier, nor the Simulator support the 3D Touch feature.

Because there’s a chance that the user may disable 3D Touch at any point, we can call this method in viewWillAppear. This will make sure it gets called when the app launches and when our main view comes back into vision. In that case, we’ll simple enable the long press gesture and the app keeps working. If the user switched 3D Touch on again, we’ll disable that gesture so it won’t interfere with 3D Touch.

We also want to call this method in traitCollectionDidChange, which is called when the user switches the 3D Touch feature on or off (among other occasions). Here’s how we do that:

This content is for members only.

Make sure to implement a method that can dismiss the preview view controller, otherwise it’ll just sit on top of the stack and not go away again.

When the user swiped up while the preview view is displayed, we can display what’s known as Preview Action items. I’ll discuss this in my next article.

Implementing Pop

Once the preview is presented, the user can elect to press deeper to switch to another view controller. Again, all we have to do is to conform to the second method of our above protocol. This one is called previewingContext:commitViewController:viewControllerToCommit.

Just like before, I’ll instantiate a view controller from my storyboard here.

This content is for members only.

Further Reading

How to avoid “whose view is not in the window hierarchy” error when presenting a UIViewController

Screen Shot 2015-09-23 at 10.19.53

When you present a view controller from another one, iOS will do it just fine but may complain with something along the lines of the following error message:

Warning: Attempt to present <SecondViewController: 0x7fb54b523240> on <ViewController: 0x7fb54b61e7f0> whose view is not in the window hierarchy!

This can happen when you present the second view controller with a simple method like this:

[self presentViewController:secondView animated:YES completion:nil];

What iOS has a problem with is that “self” may not be the top most view controller in the window hierarchy, from which ordinarily another view controller should be presented. Think of presenting view controllers using a navigation controller: “self” doesn’t do it; instead the navigation controller must do it, being higher up the hierarchy than the current view controller.

So rather than present from “self”, we should be presenting from the top most view controller in our keyed window, like so:

UIViewController *top = [UIApplication sharedApplication].keyWindow.rootViewController;
[top presentViewController:secondView animated:YES completion: nil];

To make sure you’re always presenting from the top most view controller, you can make use of a small helper method courtesy of akr and Darshan Kunjadiya. It goes like this:

- (UIViewController*) topMostController {
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

    while (topController.presentedViewController) {
        topController = topController.presentedViewController;

    return topController;

How to create an Unwind Segue in iOS 8

The Unwind Segue was introduced in iOS 6 to make retrieving data from a dismissed view controller easier. A regular Segue allows us to send data from one view controller to another, but it’s not easy to bring data back if the user has changed or added details in that view controller. That’s where an Unwind Segue comes in.

Part 1: Code

Here’s how to create one. I’m assuming we have two view controllers at our disposal, ViewController1 has initiated a standard segue, maybe passing some data. The user then changes the data, and upon saving the data, ViewController2 is dismissed and we’re going back to ViewController1.

So in ViewController1 we’ll add a method we can use as an Unwind Segue, which we later hook up in the storyboard to the Exit object. Here’s that method:

- (IBAction)backToTheStart:(UIStoryboardSegue *)segue {
    // grab a reference
    ViewController2 *viewController2 = segue.sourceViewController;
    // access public properties from ViewController2 here

It doesn’t matter what the method is called, just as long as it resides in ViewController1, in which you’ve imported the ViewController2.h file. What DOES matter however that our method is an IBAction and takes a UIStoryboardSegue as a parameter – otherwise Interface builder won’t recognise it, and you won’t be able to drag to the Exit object later.

Meanwhile, in ViewController2, we can make use of the following method which is often provided as a stub in new view controller classes:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // do any preparation here when the segue is called

prepareForSegue is called just before the unwind segue (or any segue for that matter) is about to begin. You may want to read out a text field or any other values and add it to the object or variable that ViewController1 needs access to.

Part 2: Hooking up the Storyboard

With our code in place, control-drag from the button you’d like to use for initiating the segue. You can hook up multiple buttons to the same unwind segue.

Control-drag each button to the Exit object (in ViewController2):

Screen Shot 2015-01-29 at 12.00.49

As soon as the button is pressed, the unwind code in ViewController1 is executed and ViewController2 is dismissed.

Demo Project

I’ve put together a quick demo project on GitHub which is the code I’m creating the screencast above:

Further Reading

How to test which class presented a UIViewController

The NSObject class has an interesting method called isKindOfClass. As the name suggests it lets you test what kind of class it belongs to. As everything we use inherits from NSObject, this method is available in our own classes we use in iOS and Mac development.

This method can come in handy for example when three different classes present the same view controller and you’d like to make decisions based on which controller has presented your content. Consider the following two example.

If you present a UIViewController via a modal segue you can test which class the presenting view controller belonged to like so:

// grab a reference to the presenting view controller 
id thePresenter = self.presentingViewController;

// and test its class
if ([thePresenter isKindOfClass:[YourViewController class]]) {
    // do this
} else {
    // do that

If however your view controller was presented via a UINavigationController then the above isn’t going to work. Instead you need to check which view controller was on the navigation stack previously.

Here’s how to do this:

// grab a reference to the previous view controller 
id thePresenter = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count - 2];

// and test its class
if ([thePresenter isKindOfClass:[YourViewController class]]) {
    // do this
} else {
    // do that