Tag Archives: UIViewController

How to fix "setPreferredContentSize" error in iOS 6 iPad Apps

xcodeThere is a bug in Xcode 5 in the Master Detail Template which manifests when you try and run it on iPads running iOS 6.x. The app will work fine on iOS 7 but won’t even start in iOS 6. The full error message is something like this:

Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[MasterViewController setPreferredContentSize:]: unrecognized selector sent to instance 0x7a95580’

The problem is with a code snippet in MasterViewController.m, first method. It looks like this:

[emember_protected]

The trouble is that self.preferredContentSize is only available in iOS 7, hence the exception. In previous versions of this template this line didn’t seem to matter – and by simply commenting it out the problem goes away, seemingly without any functionality issues.

Apple like doing this at times – which goes to show that they rather you never look back at older iOS versions.

If you don’t feel like commenting the line out completely you can test if device OS supports it by amending the whole function like this:

[/emember_protected]

Here we check if our current view controller (self) responds to preferredContentSize, and if it does, we’ll call what Apple recommend. If that’s not the case we simply won’t.

Adios exception!

How to open items in other iOS Apps

There are several ways to send items from your own app to others, one of which is custom URL schemes. But not every app supports such schemes.

Another way is to use a UIDocumentInteractionController. This is an iOS View Controller you can give a URL with an item (or items) to open in other apps or preview right away (such as image, video, ZIP file, etc).

Screenshot 2014.01.09 13.26.10

iOS will handle the display of apps capable of handling your files. It’s fairly straightforward to setup such a complex sounding controller. It even has a convenience method, but note that you must retain this in your own property, otherwise your app will crash when the delegate returns with a call back.

Here’s how you create a UIDocumentInteractionController. I’m assuming you’ve got a property for it in your class called controller:

That’s a custom initialiser, followed by a method that would preview a document in your own view controller. The presentation will include its own “open in” button as well. However, not all items can be previewed, especially not on older versions of iOS.

You can also bring up an “Open In…” dialogue like this:

Here we pass a ZIP file to our controller and try to open it in another app (such as DropBox or Goodreader). If no such apps are installed an alert view will tell the user about this. You can do the same with the Preview dialogue from earlier.

Note that for the preview option you are required to implement the following UIDocumentInteractionControllerDelegate method:

The first one is required for the preview controller to function, the latter two are optional and keep track of where your data is while passing it to another app. It’s useful to have so we can display a progress indicator of sorts while a large file is being passed on.

Demo Project

I’ve created a demo project on GitHub which demonstrates this in more detail.

Enjoy!

How to attach custom actions to an Edit Button Item (or The Dark Secrets of the Edit/Done Button)

You can create an editButtonItem in a UITableViewController like this:

If your view controller is embedded into a navigation controller, an edit/done button will show up and you can toggle its state by pressing it.

Edit-Done

That’s great, but it takes a deeper understanding of how this happens to make full use of it in your own projects.

What this button actually does is set the “editing” property of your view controller to YES or NO. If it’s YES, the button turns into “Done” (and equivalent translations), and if it’s NO then it turns into “Edit”. You won’t notice this on a standard view controller, but on derivatives (such as a UITableViewController) this has a substantial effect: the table view enters edit mode and changes appearance.

You can therefore test the state of the button by querying your view controller:

But that’s not an action, that’s just a test. If you’d like for something to happen when that edit button is pressed, you must override the following function which is called every time that button is pressed:

This method is called by the table view when that button is pressed. We’re calling the super method first, then add our own bits at the end. You can also call this method from anywhere and put the table view into or out of edit mode like so:

How to create a UITabBarController in code

Tab Bar Controllers are setup with an array of view controllers. We’ll create those first, then we simply give said array to our tab bar controller.

In this example, this is a subclass of UITabBarController:

Note that I’m also setting the title property of each view controller. This is displayed as the tab bar text and is left blank if not specified. To override this behaviour and/or specify graphics, set the UITabBarItem of each individual view controller.

The method that creates the view controllers is very straightforward: in this example I have a single ViewController in my storyboard (with a Storyboard ID of “PlainViewController”). All we do here is specify a funky background colour to tell them apart:

Note that the tab bar configuration is not set in stone: you can switch out the view controllers on the fly by calling the setViewcontrollers method again, passing in new content.

Here’s a full working demo project that show it all in action:

and the class reference:

How to dismiss a Popover from the current UIViewController

Imagine you’re presenting a view controller in your storyboard via a Popover Segue: Simply drag from a button in your Main View Controller to your Other View Controller, and under segue select “Popover”. Works like a charm: the popover is presented, and if someone clicks outside the popover it is dismissed. Marvellous!

Surely we should be able to add a button inside our popover, and create an IBAction in which we call something like “dismissPopover:animated”. But of course there isn’t – at least not if you’re presenting a UIViewController.

Things would be easier if we had created our popover in code, where we could create a UIPopoverController (which has a method that dismisses it) – but if you’ve ever tried, that’s just not possible when using Storyboards: because with Storyboards, all we can create is a UIViewController, and it just doesn’t have a popover dismissal method.

So how do we do this instead?

[emember_protected]

First we’ll create a reference to the UIPopoverController the segue will initiate for us, then we’ll call the dismissPopover:animated method on it from the class that has presented it via an observer.

Let’s do this thing!

In our Main View Controller (i.e. the one that’s bringing up the popover), we’ll add a weak property to hold that reference. We’ll also need two methods, the prepareForSegue:sender, and one to dismiss the popover. We also need to setup an observer:

Nothing unusual here, except perhaps for how we grab the reference to the UIPopoverController. We’re typecasting the segue as a popover segue so we can extract the actual popover controller from it.

Note that I’ve named the popover segue in the storyboard (as settingsPopover). The dismissPopover method is something that we’ll call via an observer, setup in viewDidLoad.

Next up: the actual UIViewController that we’ve created in the storyboard. This will serve as the content for the popover controller which will be generated automatically for us via the segue that’s defined as “popover segue” in the Storyboard. All we do here is to hook up that “dismiss button” to an IBAction which in turn will send a message:

[/emember_protected]

This notification is picked up by our Main View Controller which acts accordingly and can dismiss our popover because it holds a reference to it.

Another mystery solved 😉

How to create a View Controller defined in you your Storyboard programmatically

Your View Controllers are created by the Storyboard automatically depending their defined relationships in Interface Builder.

Sometimes however we need to create and transition to View Controllers we’ve defined in code. For example, if you want to transition to a view as part of displaying a search result.

We can do this by creating a new UIStoryboard object and then asking it to create a View Controller defined in it. For this to work you need to give your View Controller a unique identifier using the Identity Inspector (under Identity, set a Storyboard ID).

This example assumes we have a Storyboard file called MainStoryboard.storyboard in which there’s a View Controller called DetailView. Here’s how we create it and push it onto a stack of Navigation Controllers:

[emember_protected]

Note that you define the Storyboard without its extension. If the bundle parameter is nil (as it is here) then the compiler assumes your main bundle.

[/emember_protected]