UITabBarController inside Master View of UISplitViewController

An iPhone only chat application.

If you need to create a Messenger/Telegram/WhatsApp like interface for iPhone you can start by simply taking Xcode provided Tabbed Application template and personalize each view controller as desired to get your interface flow working. This includes various transition by segue or pushViewController, device rotation, autosizing etc…

A Universal chat application.

For a Universal iPhone and iPad chat application it becomes more complicated, this isn’t that simple…
iOS SDK isn’t really good in providing acceptable default behavior when you combine some simple interface elements to obtain a complex one. For a Universal app we must modify the Storyboard by adding UISplitViewController, make it the Storyboard Entry Point and move the UITabBarController in such way to replace Master View Controller. Or start with Master-Detail Application example and go the other way around. Choosing the later one you must end with something similar to this storyboard:
Storyboard with UITabBarController inside MasterView of UISplitViewController

I aim to misbehave.

On an iPad, this setup works pretty well, but on iPhone and iPhone Plus the default implementation tends to misbehave terribly. In a compact horizontal size class, like in portrait and landscape orientation on iPhone or in portrait orientation on iPhone Plus, when you tap on a table view item the detail view controller is presented as a modal popover with no controls to close it. This is because UITabBarController, placed as replacement of UINavigationController of Primary view of UISplitViewController, to behave correctly, must override -showViewController:sender: method called by UISplitViewController in horizontally compact size. But it doesn’t and default implementation presents the incoming detail view controller modally.

We can solve this in three ways:

  • by subclassing UITabBarController and override -showViewController:sender:
  • by subclassing UISplitViewControllerDelegate and override -showDetailViewController:sender:
  • by implementing the UISplitViewControllerDelegate optional protocol method -splitViewController:showDetailViewController:sender: of UISplitViewController delegate

All solutions are similar, when show[Detail]ViewController is called, you need to take the incoming UIViewController, cast it to UINavigationController, get the topViewController and push it on selectedViewController of your UITabBarController. Code speaks better:

Now we are good in portrait orientation, but try to rotate iPhone Plus to landscape and you will see that the detail view controller is on the left side of the split view controller and not on the right where it must be… This is again because UITabBarController is asked to handle the transition to not collapsed regular horizontal size class via -separateSecondaryViewControllerFromPrimaryViewController: but it doesn’t implement it.

Compact to Regular

As above we can solve this in three ways. General steps are to check if the topmost view controller is a DetailViewController, if so pop it from the navigation stack, embed it in a UINavigationController and return the result to UISplitViewController.

And back to Compact

Now if you rotate iPhone Plus back from landscape to portrait you will lose the DetailViewController from your navigation stack. To preserve it you must manually push it back to one of the UITabBarController views UINavigationController‘s.

Debug tip

To see yourself how controller hierarchy change with various screen sizes and with orientation change, place a breakpoint in each of delegate calls and print the whole view controller hierarchy in LLDB console with po [[[UIWindow keyWindow] rootViewController] _printHierarchy].

Long live HTTPS!

HTTPS encrypted connection

I’ve started from the scratch and get rid of blog sub-folder.

BACKUP PLAN: FORMAT C:\

Then I’ve tried to add again the http to https redirect in .htaccess and got the server unavailable error from CloudFlare. This is because Altervista hosting server was not presenting to CloudFlare any certificates. Soooo… screw redirect, if you want to browse in http, for now, I’ll not force you to go https. Let’s concentrate on flawless https experience by fixing ‘Mixed content’ warning.

MIXED CONTENT

occurs when initial HTML is loaded over a secure HTTPS connection, but other resources (such as images, videos, stylesheets, scripts) are loaded over an insecure HTTP connection.

Again several solutions:

  • Using the CloudFlare http to https redirect was kinda working, but post featured image was still loaded over http.
  • Finding all http occurrences and replacing with https in entire WordPress source code was again kinda working, but post featured image and add plugin preview frame were still loaded over http. Also, each time when a new version of WordPress came out I need to do update manually, so go back to pristine source code.
  • Using a http to https plugin was kinda working, but external links, like one to gravatar avatar, was still loaded over http. Easily fixed by adding another replace in plugin source, but still kinda hacky.

In extremis I’ve tried the simplest solution: set the WordPress Address (URL) and Site Address (URL) to https://… and it worked! No more ‘Mixed content’ warning! And with added benefit of automatic redirect from http to https!

CONCLUSION

If you deal with a free hosting, don’t overthink and do the simplest thing you can. Otherwise, you get in troubles that you can’t debug and loose your precious time.
If you want to tweak all parameters at your will, get yourself a virtual server, or at least a paid hosting with a good reputation and many personalization options.

In the beginning there was HTTP…

Signage: one way, wrong way, do not enter
…but we are in 2017 now

and HTTPS is a must standard, and the fact is, I wanted to have this blog running entirely on a secure connection. My initial plan was to leave the root folder for a future personal website with portfolio, about me and etc. sections and a link to blog in separate folder where I’ll install WordPress.

Installing

With my plan in one hand and FileZila in other I’ve installed WordPress in a couple of minutes. For SSL encryption I need a valid certificate, Altervista hosting can give you a free HTTPS certificate, although it’s not generated by them but by their partner CloudFlare and to get it you must also enable the whole CDN (Content Distribution Network) stuff supplied by CloudFlare. So this was also done.

Redirect

Now we must enable automatic redirect from root to blog folder and .htaccess with mod_rewrite seemed like a reasonable way to go. After a bit of googling and trial and error this is what I came:

BTW follow this link for an excellent mod_rewrite cheat sheet by Dave Child.

Get rid of HTTP

Next step was to redirect each HTTP request to it’s HTTPS counterpart.
Googling the simplest solution is to set the WordPress Address (URL) and Site Address (URL) from http to https. Doing this made the site go in redirection loop.
An alternative was to use .htaccess with another rewrite condition added right after the previous redirect:

Doing this made the site go in redirection loop, again.
Other solutions failed too, and as I found the problem was not my scripts, but the CloudFlare and how they manage https connection.
Remember that I was forced to enable CloudFlare to have a https connection? As it turns out after Altervista made partnership with CloudFlare all connections and request go to CloudFlare over https/http connection, and then CloudFlare contacts Altervista on regular http. And only CloudFlare is allowed to contact Altervista servers over http.

Conclusion

Sometimes it’s really a pain to bump against free hosting limitations… Next time I’ll see hot to fix it!