Search code examples
iosobjective-ccore-datadelegatesmaster-detail

Why are my delegate methods never called?


I've tried to set up a very basic delegate between a TableViewController and a DetailViewController, but the methods are never called. Here's my code:

DetailViewController.h

@protocol DetailViewControllerDelegate

- (void) detailViewControllerDidLike;
- (void) detailViewControllerDidUnlike;
- (void) detailViewControllerDidDislike;

@end

DetailViewController.m

- (IBAction) changeLikedSwitch: (id) sender
{
    UISwitch *likedSwitch = (UISwitch *) sender;
    if ([likedSwitch isOn]) {
        [_selectedQuote setIsLiked: [NSNumber numberWithBool: YES]];
        [self.delegate detailViewControllerDidLike];
    } else {
        [_selectedQuote setIsLiked: [NSNumber numberWithBool: NO]];
        [self.delegate detailViewControllerDidUnlike];
    }

    NSError *error;
    if (![[[CDManager sharedManager] managedObjectContext] save:&error]) NSLog(@"Saving changes failed: %@, %@", error, [error userInfo]);
}

- (IBAction) changeDislikedSwitch: (id) sender
{
    UISwitch *dislikedSwitch = (UISwitch *) sender;
    if ([dislikedSwitch isOn]) {
        [_selectedQuote setIsDisliked: [NSNumber numberWithBool: YES]];
        [self.delegate detailViewControllerDidDislike];
        [self dismissViewControllerAnimated: YES completion: nil];
    } else {
        [_selectedQuote setIsDisliked: [NSNumber numberWithBool: NO]];
    }

    NSError *error;
    if (![[[CDManager sharedManager] managedObjectContext] save:&error]) NSLog(@"Saving changes failed: %@, %@", error, [error userInfo]);
}

TableViewController.h Interface line:

@interface TableViewController : UITableViewController <NSFetchedResultsControllerDelegate, DetailViewControllerDelegate>

TableViewController.m

- (void) detailViewControllerDidLike
{
    NSLog(@"detailViewControllerDidLike!");
    [self.tableView reloadData];
}

- (void) detailViewControllerDidUnlike
{
    NSLog(@"detailViewControllerDidUnlike!");
    [self.tableView reloadData];
}

- (void) detailViewControllerDidDislike
{
    NSLog(@"detailViewControllerDidDislike!");
    [self.tableView reloadData];
}

None of these methods are called. I'm trying to work out whether it's because I haven't set the delegate, but I don't understand how I can do that. There isn't an instance of my DetailViewController in my TableViewController, so how am I supposed to set one of its properties? Isn't the whole point of having a delegate that I don't need to create a concrete link between the classes? Very, very confused here.


Solution

  • You do need to set the delegate, for delegate methods to be called.

    You must have a class that creates both the TableViewController and the DetailViewController? when they are created you would call

    [myDetailViewControllerObject setDelegate:myTableViewControllerObject];

    to set the delegate. This is assuming you've defined a delegate property in DetailViewController with

    @property (readwrite, weak) id<DetailViewcontrollerDelegate> delegate;
    

    A further explanation of delegates:

    The point of a delegate is so that you don't need a specific type of object, you only need an object that implements the protocol. There still needs to be a connection between the delegate and the "delegator". If you want no concrete connection, then you would want to use an NSNotification, which is very much a "shout into the ether, and hope something is listening" method of communication.

    In this case, a delegate is the correct thing to use. Delegates should be for one-to-one relationships, NSNotification are best used for one-to-N type relationships, where N can be 0 or more.