Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delegate vs Unwind Segue for Passing Data to Parent Scene

Since iOS 6, unwind segues have been available to navigate up the scene hierarchy. I am trying to decide on the cleaner/better/preferred/more maintainable method for passing data to a parent view controller. There are some questions that address this from the technical perspective (e.g. "if I have an unwind do I still need a delegate") but I can't find much that addresses the questions of pros/cons.

Option 1: use a delegate.

  • Done by passing in the parent view controller as a delegate adhering to a protocol.
    • Child calls the protocol method to return the data.
    • If data validation is required by the Parent, return value/dict required to allow child to handle error.
  • Overhead: Protocol definition and one method in the parent (for data validation and receipt).

Option 2: use an unwind segue

  • Done by calling the unwind segue from the child.
    • Child adds a segue on its scene by dragging a button or the storyboard itself to Exit and naming the segue so it can be with performSegueWithIdentifier:sender
    • Parent implements returnFromSegueName (user named method linked to that segue) to grab the data from the child.
    • Data validation though can only be implemented by also implementing canPerformUnwindSegueAction:fromViewController:withSender
      • Data validation failure will require another property on the Child as this method only accepts a BOOL for return value.
  • Overhead: Two methods, an extra property, plus Storyboard shenanigans.

Overall, delegates are feeling like the cleaner way to go, but perhaps also antiquated. Am I wrong to be leaning in that direction?

like image 780
El Tea Avatar asked Oct 24 '13 02:10

El Tea


People also ask

What does unwind segue do?

What is an unwind segue and how does it work? An unwind segue lets you jump to any view controller further up your view controller hierarchy, destroying all view controllers preceding the destination. Before actually creating one, let's overview how an unwind segue works.

How to dismiss a segue?

Connect a triggering object to the exit control Select one of the action methods to complete the unwind segue. You only select the action method, not a specific view controller. To be displayed after the dismissal, a parent view controller must implement the method you select.


2 Answers

I realize now that this isn't truly an answerable question other than to say that neither approach is wrong - they both have their pros and cons. After having tackled both for a week and done more reading on the subject I can at least quantify why you might want to use either an unwind segue or delegates for working between view controllers.

Coupling

Both models are roughly equally (loosely) coupled. Under the hood, an unwind segue is just a delegate where iOS has done the work of wiring it up for you. For delegates, the parent knows about and conforms to the child protocol. For unwind segues, the parent has to be wired to the child on the storyboard for unwind and needs to know the properties of the child to extract the return data. However, if you're new to delegates and just want to get some data out of a child view, unwind segues are probably less intimidating than using protocols with delegates.

Flexibility

Unwind segues are only a good choice if the sole purpose of the child-to-parent interaction is to return data. There does not appear to be a way to cancel an unwind segue in progress. So if the parent has to do any data validation, or if the child needs more than one interaction with the parent, the only way to do this is to have a delegate where multiple methods can be called back to the parent.

Maintainability

If the type or other aspects of the data being returned changes, it will be easier to update the unwind segue as all you have to do is to update the code in your unwind segue to look at the new properties. For the protocol/delegate approach, you will have to update the protocol in the child and the implementation in the parent. However, the simplicity of the unwind segue comes at the cost that you may easily miss places in parent view controllers that require updating because you don't have the compiler checking your contract (the protocol).

The Winner

There isn't one. Which way you go depends on your data needs, comfort level with protocols (they look more intimidating on first glance than they should), complexity of your application, and long term maintenance needs.

For my purposes, I wound up using delegates because my child had to make more than one call back to the parent in some cases. However, in a few instances where I had many pieces of data to pass back, I adopted what I learned from the unwind segue and simply used properties in the child from which the parent could extract the needed information. I also used this as a convenient path for the parent to provide error information to the child. I don't mix and match unwind segues with delegates in the program for consistency with a programming partner, but there's no reason you couldn't do that if you wanted to.

like image 194
El Tea Avatar answered Oct 06 '22 04:10

El Tea


I was very skeptical of storyboards, but I decided to dive in and use them on a new project. I was amazed at the ease with which you can communicate between the two view controllers. When you perform a performSegueWithIdentifier you get a handle to the new ViewController. You can set any exposed properties you want in that new viewController very cleanly and nicely.

Here is an example:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"showDetail"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        Student *student = [self.students objectAtIndex:indexPath.row + [self rowAdjuster]];
        [[segue destinationViewController] setStudent:student];
    } 
}

It is very nice and neat. No special protocol that you need to track or maintain.

And Then coming back (I have an IBAction connected to a button in my detail view) You can once again get a nice clean reference to the viewController to which you are returning, and act upon that viewController.

- (IBAction)returnWithStudent:(UIStoryboardSegue *)segue {
    UIViewController *vc = [segue sourceViewController];
    if ([vc isKindOfClass:[ AddStudentViewController class]]) {
        AddStudentViewController *addViewController = (AddStudentViewController *)vc;
        if (addViewController.student != nil) {
            if ([addViewController hasTakenPhoto]) {
                [PhotoHelpers saveImageForStudent:addViewController.student];
            }
            [StudentController updateStudent:addViewController.student];
        }
    }
}

Also the segue logic control is nice. One can perform logic checks in shouldPerformSegue which are quite handy.

I've seen lots of junky code that uses protocols of the "send something back to caller" that are really poor at coupling classes. It makes a three-way arrangement-- viewController1 -> protocol -> viewController2, whereas segues make a nice arrangement of viewController1->viewController2.

The segue is a nice way to cleanly and uniquely couple the two classes. I'd strongly recommend it.

like image 29
HalR Avatar answered Oct 06 '22 06:10

HalR