'Show' Adaptative Segue Error

{% github esttorhe ShowNotWorking_Radar 5f81558 %}

On our projects we use multiple UIStoryboard files to break our apps; yes, we use storyboards, we are drinking Apple's "Kool-Aid" and personally they are real time savers and let us focus on improving the experience and enforcing the business rules.

Fist Glimpse Of The Problem

Although this "embracing the change" would come to hunts us with a weird bug that was reported to us; hitting a "share" button was yielding no actions…

That's weird since we have it "wired" to launch a UIActivityController that will handle our sharing list.

Let's open Xcode and launch the simulator… nope, everything works as expected.

Time to connect our device; load the latest build, run and… nope, can't reproduce.

Isolating The Bug

After writing back to the reporter we got word that the issue is happening on an iPhone running 7.1.

With that we go to Xcode, rinse and repeat with the exception that this time there's nothing happening after hitting the share button.

We immediately noticed that the UINavigationBar was missing from the "sharing" view controller and internally we were presenting the UIActivityController like this:

UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[self.currentUser.myList.itemProvider] applicationActivities:nil];
// Adding some exclusions, etc 
[self.navigationController presentViewController:activityViewController animated:YES completion:^{
    // Do some other stuff
}];

Just from looking at the code plus the lack of navigation bar we can infer that our navigationController property was nil.

After debugging its confirmed; it is nil; but not just that; the child view controller is being presented modally… so… iOS somewhere is taking the child view controller out of its hierarchy and its presenting it completely isolated as a "modal" leaving the user stuck (because it was coded assuming a Back button on UINavigationBar added after the push).

But WHY??

I went to Apple's documentation regarding this new "adaptive segues" (because if you didn't know Push, Modal, Popover & Replace are now deprecated) and this is what I found: From Apple's Documentation: https://developer.apple.com/library/ios/recipes/xcodehelp-IBstoryboard/chapters/StoryboardSegue.html

From the documentation we can take that during a "regular" usage of the Show segue on an iPhone app that's not showing a master/detail the segue will behave as a now deprecated Push segue.

To add to the weirdness everything works as expected on iOS8 but it doesn't on iOS7.

With that in mind I went to Xcode with the sole idea of generating a project that could easily reproduce the issue.

New Project, open the storyboard; throw a UINavigationController; set its rootViewController, one UIButton, connect its action to Show and that to another UIViewController; now lets create some code for that child view controller that should display a UIActivityController upon viewDidAppear::

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:@[@"Test"]
                                                                             applicationActivities:nil];
    [self.navigationController presentViewController:activityVC animated:YES completion:^{
        NSLog(@"This line will never execute on iOS 7.1");
    }];
}

And voilà; compile and run on iOS8; everything works.

Close, compile and run on iOS7… everything works.

YES… no wait… the code is working correctly on both environments. Cleaning and building again did not introduce the issue.

Consistently Reproducing The Bug

I was just about to give hope on this when I remembered something. In our project we have a "hamburger" menu (something for another post) which "replaces" the top view controller via code before using all the segues from the storyboard.

Perhaps that's the issue; let's make a couple of modifications.

First let's add an "extra" level on our storyboards; so that we now have something like this:

--- UINavigationController
    --- Root View Controller
    --- Pushed 1st View Controller // Via Code
    --- Pushed 2nd View Controller // Via `Show` segue

And from the 1st view controller let's push the 2nd one with some boilerplate code:

UIViewController *vc = 
[self.storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
[self.navigationController pushViewController:vc animated:YES];

Compile and run on iOS8 everything works

close compile and run on iOS7 and… there you go.

Last UIViewController is being presented modally instead of pushed to the current stack; thus, its navigationController property is nil.

Conclusion

This is obviously a bug introduced by Apple that does not support "retro compatiblity" of this new adaptative segues.

We should be able to replace the deprecated Push with this Show and it should behave the same unless we are taking advantage of this whole new "master/detail" containers approach.

I filed a radar with this issue, please feel free to duplicate with that hopes that Apple fixes it.

Also here's the code with a project that easily reproduces the issue.

Workaround

For now the only "solution" is changing the Show segue for a Deprecated Push; this looks like (and is ) code smell but its the only viable solution for now.

UPDATE

Recently I got an update on my radar from  with the following response:

Adaptive segues like Show are only supported when running on iOS 8 or later. Interface Builder is failing to warn that this segue will not be properly unarchived on iOS 7.

We are continuing to work on this issue, and will follow up with you again.

So there you have it;  kind of accepted it as a bug (at least on IB not warning) but at the same time is telling us that pre iOS8 adaptative segues could have unexpected behavior.

Long story short; DON'T USE THEM if you need to support older OS versions.

Posted by Esteban Torres on 12/16/2014


Comments

Comments are published on the website GitHub repository. You can leave a comment on this post's issue. Your comment will show up automatically on this page.