Search code examples
xcodedelegatesmaster-detailuistoryboard

iOS Master-Detail app: defining protocol, delegates


In the master-detail application template (using ARC, storyboards) in XCode 4.3.2, I am trying to change (more specifically replace) the detail view when an item in master table view is selected. I am trying to implement delegates/protocols for this.

What I am confused about is - which class should implement the methods defined in protocol - master or detail?

Having the detail view implement the protocol method makes sense to me since, I'll be push/popping the view controllers in detail view based on the selection (passed as a string from master via the protocol method).

Here's what I tried

1) Defined the protocol in MasterViewController.h

@protocol MasterViewDelegate <NSObject>
- (void)masterSelectionChanged:(NSString *)selection;
@end
@interface MasterViewController:UIViewContoller
@property (nonatomic, weak) id <MasterViewDelegate> delegate

2) in MasterViewController.m

@synthesize delegate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [delegate masterSelectionChanged:@"Some string based on indexPath.row"];
}

3) in DetailViewController.h

#import "MasterViewController.m"
@interface DetailViewController:UINavigationController <MasterViewDelegate>
@end

4) in DetailViewController.m

#pragma mark - MasterViewDelegate
- (void)masterSelectionChanged:(NSString *)selection
{
    NSLog(@"the selection is: %s", selection);
    // WIll push/pop view over here, may be perform segues based on selection
}

In this process, upon selecting the rows in master table, nothing happened. No crash, no display of log, no error while building either. What did I miss over here?


Solution

  • You need to set the delegate property - at the moment it will be nil so nothing happens when you send messages to it. In the iPad template you can do this as follows, in the viewDidLoad of your detail view controller:

    [super viewDidLoad];
    if (self.splitViewController) // Means this won't be called if you use this code on iPhone too.
    {
        // According to comments your master controller is embedded in a nav controller
        UINavigationController *nav = (UINavigationController*)[self.splitViewController.viewControllers objectAtIndex:0];
        // I am assuming it is the root view controller
        MasterViewController *master = (MasterViewController*)nav.rootViewController;
        // Finally set the delegate
        master.delegate = self;
    }