Monday, September 17, 2012

Referencing a UIViewController After Embedding

The UIStoryboard is a timesaver. However, as with everything else, there are always little tricks that befuddle us all. Today, I had a regular modal segue that went from one UIViewController to a second UIViewController. When the segue fired, I set a delegate reference. Everything worked wonderfully!
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue destinationViewController] respondsToSelector:@selector(delegate)])
    {
        [[segue destinationViewController] setDelegate:self];
    }
    
}
However, I now decided that I needed to embed one of my UIViewControllers in a UINavigationController so that I could browse some more data in that part of my app. However, now, the code above did not assign my delegate to my UIViewController. The reason for this is that the [[segue destinationViewController]] was not pointing to my UIViewController. It is now pointing to the UINavigationController.

To fix this, I took advantage of two things:
- segue's can have names
- you can cast an object

Here is new code that will reach through the UINavigationController to my UIViewController and set the delegate.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"detailSegue"]) {
        UINavigationController *tempController = [segue destinationViewController];
        if ([[tempController topViewController] respondsToSelector:@selector(delegate)]) {
                   [(DMTW_ArticleDetailViewController*)[tempController topViewController] setDelegate:self];
        }

    }
    
    if ([[segue destinationViewController] respondsToSelector:@selector(delegate)])
    {
        [[segue destinationViewController] setDelegate:self];
    }
    
}

We can see here that for all of the other segues we will just set the delegate like always. However with the segue of "detailSegue" we will do something different. We will first cast the [segue destinationViewController] to be a UINavigationController and then we will check the topViewController to see if it responds to "delegate". If it does we will set the delegate.

Notice, we are being a little lazy with this line.
 [(DMTW_ArticleDetailViewController*)[tempController topViewControllersetDelegate:self];
We probably should have kept the same two line format as we did for setting tempController as a UINavigationController and done something like
DMTW_ArticleDetailViewController *tempArticleController = [tempController topViewController];
[[tempArticleControllersetDelegate:self];
But, where's the fun in that? If you are running into a similar issue, hope this helps clear it up for you.

No comments:

Post a Comment