Saturday, November 23, 2013

Storyboard and unwind segue

With iOS 5, storyboards made their entrance, with iOS6 they went popular and with iOS7, there're well settled. I've sparely used storyboard in the past and when a friend of mine told me about unwind segue, I thought it was time to revisit it. Here's my story:

A bit of history

First there was Interface Builder

Interface Builder (IB) allows you to work on a graphical interface to define you app layout and components. Customising a table view cell through IB saves you tone of UI code that clutters your app.

Does IB generate code behind the scene? Not quite, it's not really code that is generated when you use storyboards or nibs. The views are encoded into a binary file (using NSCoder) and decoded at runtime. Think of it as the objects being created and frozen in Interface Builder, then defrosted during runtime.

Then came Storyboard

Storyboard goes one step further...

As the name said it all, it's about putting the story of your app on a board. With IB you can work with one view, with storyboard you can have multiple views on a same board. It introduces segues. Segues represent transitions between screens. Opening a storyboard and your have pretty good idea of the UI flow at a glance. In XCode 5, application templates scaffold storyboard by default (no check box to ask you). So when I switch to iOS7, I thought it was time to give storyboards another trial and I had a perfect use case for that.

On the AeroGear project, we have a great Android Cookbook where you demo the features of the libraries without being cluttered by too much UI code. I thought having a version for iOS will be wonderful.

Storyboard and its segue

So I settled on writing one and I thought it was a great use case for using storyboard. I was new to it, I already tried and actually blog about it here. Coding with storyboard I've discovered unwind segue and I love it. You can replace delegate with unwind segues. Making even less to write.

Let's see it with an example

Taken from iOS cookbook, Xmas is a short example where we have 2 view controllers: "Gifts list" controller (let's name it VC1) and "Add present" controller (VC2) as shown in XCode storyboard.

We are going to create a segue from scene one (list controller) to scene two (add present), implementing prepareForSegue:sender: in VC1.

Going from VC1 to VC2

In storyboard with the magic keys combinaison ctrl+drag from VC1 to VC2, choose the push segue. In the code implement prepareForSegue:sender: to move data from VC1 to VC2:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
 if ([segue.identifier isEqualToString:@"addPresent:"]) {
        // nothing to do
    if ([segue.identifier isEqualToString:@"updatePresent:"]) {
        // pass selected gift from VC1 to VC2
        AGAddPresentViewController* destinationController = segue.destinationViewController;
        destinationController.toWhomTextField.text = [_store read:_currentGiftId];
But what about transitioning and sending context back in the other direction? with iOS 6, we have a new technique named unwind segues...

Going back: VC2 to VC1

Now you add a new present and you want to be able to hist save and go back to the list controller. Prior to iOS6, going back was implemented using well known Delegate approach. With iOS6, we can do it with unwind segue. In you VC1 controller (the controller you want to unwind to), you have implement an IBAction method with one parameter segue, called it whatever you want. Then, from the story board ctrl+drag from ViewController to its exit icon. Xcode gives you a list of possible unwind methods (here we have implemented only one), choose it and you're done!
-(IBAction)unwindToRootVC:(UIStoryboardSegue *)segue {
    AGAddPresentViewController* source = segue.sourceViewController;
    // Get data from source
    NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
    dict[@"toWhom"] = source.toWhomTextField.text;
    dict[@"description"] = source.description.text;
    // save data in the list
    [self saveData:dict withPassword:source.password.text];
    [self.collectionView reloadData];
Elegantly in a few lines of code and some ctrl drag and drop magic we've got everything settled. You can find the complete code for this example in my github repository.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.