views:

2374

answers:

6

I'm doing an iPad tech demo and I'm running into a serious technical problem.

I have an app concept that leverages UISplitViewController, but NOT as the primary controller for the entire app.

The app flow could be described roughly as this:

Home screen (UIViewController) List->Detail "Catalog" (UISplitViewController) Super Detail Screen (UIViewController but could conceivable also be a child of SplitView).

The problem is in the flow between Home and Catalog. Once a UISplitViewController view is added to the UIWindow, it starts to throw hissy fits.

The problem can be summarized at this:

When a UISplitView generates a popover view, it appears to then be latched to its parent view. Upon removing the UISplitView from the UIWindow subviews, you will get a CoreGraphics exception and the view will fail to be removed.

When adding other views (presumably in this case, the home screen to which you are returning), they do not autorotate, instead, the UISplitView, which has failed to be removed due to a CG exception, continues to respond to the rotation instead, causing horrible rendering bugs that can't be just "dealt with". At this point, adding any views, even re-adding the SplitView, causes a cascade of render bugs.

I then tried simply to leave the SplitView ever present as the "bottom" view, and keeping adding and removing the Home Screen from on top of it, but this fails as SplitView dominates the Orientation change calls, and Home Screen will not rotate, even if you call [homeScreen becomeFirstResponder]

You can't put SplitView into a hierarchy like UINavigationController, you will get an outright runtime error, so that option is off the table. Modals just look bad and are discourages anyway.

My presumption at this moment is that the only proper way to deal with this problem is so somehow "disarm" UISplitViewController so that it can be removed from its parent view without throwing an unhandled exception, but I have no idea how.

If you want to see an app that does exactly what I need to do, check out GILT Groupe in the iPad app store. They pulled it off, but they seem to have programmed an entire custom view transition set.

Help would be greatly appreciated.

+4  A: 

Apple states:

The split view controller’s view should always be installed as the root view of your application window. You should never present a split view inside of a navigation or tab bar interface.

This does mean it should be root view and not subview of another view. Even though they add:

You should never present a split view inside of a navigation or tab bar interface

That does not mean you can add it as a subview of any other controller either. (sorry)

I have a feeling that what you are experiencing is the byproduct of trying to do so. I am actually surprised that GILT Groupe's app did not get rejected. Apple has a tendency to enforce these HIG guidelines rather strictly lately. They (as you found out already) cause a rather nasty runtime error when you attempt to add them to a NavigationController.

Jann
Correct. I've actually "worked around" this problem for the time being, but making the SplitView the root, and presenting all other views as full screen modals with transition. I am willing to bet that GILT is probably doing something similar with some custom modal transitions.It's very disheartening that Apple would release a control of such great usefulness and have it come with so many restrictions.Apple's guidelines also prescribe against over-using modals... but what choice do they give us in this scenario?
Jasconius
+1  A: 

I've solved this for myself... actually worked around... by presenting all other possible full screen views as modals of the SplitView...

This is an unsavory way of doing things in my book, but Apple leaves you little choice if you want to leverage a SplitView only "sometimes" within an app.

Jasconius
hey Jasconius..i am trying to do same as you are even i am looking at Gilt a app. i need exact same.can you post some sample code? that would be great help..thanks
Nnp
+2  A: 

I had some success by creating a second UIWindow. I associate the UISplitViewController with that, and switch it out with the main window when I want to show the splitview. It seems to work they way I wanted, except for a slight delay in rotations and a log message about "wait_fences".

g051051
Great idea. How gracefully does that handle orientation changes though?
Jasconius
Seems to work fine. Orientation on both windows tracks the physical orientation of the device, just like you'd expect, regardless of which one is visible. The only drawback is that the "wait_fences" error produces a slight visual hiccup in the rotation. Probably not production quality, but good enough for my demo.
g051051
A: 

I solved this issue by removing all the Window's subviews before add the SplitViewController.view into the Window. The rotating works fine.

However, there is a issue that if I'm viewing the MainViewController in landscape mode, then I press the button to add the SplitViewController, the Window is not catch the current orientation as Landscape and only display in size: 768x1024. This make my DetailsView in SplitViewController is only displayed a half of its size. Everything works fine after I rotate the device.

I have worked around for whole day but got no luck T_T. I'm appreciate for any help.

Tuannd
A: 

Unless your developing for jail-broken devices then bending apples rules/wishes isn't a good idea. Like Jann and Jasconius state above this means keeping a splitView controller view root, not over-using modals (vague) and not using multiple windows.

Also, the Gilt app is only available in the US

I'v been trying to find a solution too and have ended up programatically removing views from the window like Tuannd talks about but the landscape rendering bug is unforgivable.

@Jasconius, What is the max number of modals are you are presenting at any time?

Luke Mcneice
Well, no more than one because that seems to be all you can get away with easily. If I have to I'll manually place subviews in. I'm off that project now and on to a fresh new hell of custom controls for the iPad. The orientation management for the iPad is just a damn shame.
Jasconius
A: 

I am struggling with this same issue. I've been trying various things poking at the UISplitViewController as a black box and see how it reacts.

I seem to have come up with a solution to my case which seems to be working satisfactorily.

The key appears to be that the first view added to the UIWindow is the only view properly initialized. All the problems I've had tend to stem from incorrect notification of the orientation of the device. The first view added, apparently has this correctly configured.

In my case I didn't want the UISplitView as the first view. The following is working for me.

The app delegate application:didFinishLaunching method is special. Adding the view to the UIWindow must occur here. If it is done elsewhere it does not get configured properly.

Essentially the magic sauce, is have the split view be the first view added to the window. Its then ok to remove it as long as you retain the UISplitViewController. From then on you can swap other views in and out, including the UISplitView and most things seem to be ok.

I've still run into a few issues. Popovers on views other than the split view are confused on the views frames and location of toolbar buttons and will display in the wrong location. I place then in a specific location and that seems to handle that case.

If a popover on the split view is still displayed, and you try to view another view, the orientation of the second view is confused and shows up sideways. If that view is accessed before the popup is displayed, all is well. I've fixed this my manually dismissing the popover before switching to any other view.

Here's the code if it helps. All the controllers are instance variables of appDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // This also seems to work as good magic. Seems to set orientation and size properties that persist.
    [window addSubview:splitViewController.view];
    [splitViewController.view removeFromSuperview];

    [self switchToNewViewController:firstController];
    [window makeKeyAndVisible];
    return TRUE;
}

- (void)switchToNewViewController:(UIViewController *)newViewController {
    [popoverController dismissPopoverAnimated:FALSE];
    if (newViewController != currentViewController) {
        [currentViewController removeFromSuperview];
        currentViewController = newViewController;
        [window addSubView:newViewController.view];
     }
}
David
That's a good insight about adding then removing the split view in appDidFinishLaunching. The "root view controller" thing and bad orientation notifications has been a well established problem, something totally exacerbated by the fact that SplitView can't be a subview. In a rational universe (read: basically any app that doesn't use SplitView) you always have a generic RVC that sends down orientation info to its children. Splitview shatters this. You're better off literally making your own Splitview.
Jasconius