0

I have a method called dateSelectViewController declared in my .h file as a protocol:

@class DateSelectViewController;
@protocol DateSelectViewControllerDelegate 

- (void)dateSelectViewController:(DateSelectViewController *)sender
                         theDate:(id)stringDate;

@end

Below the protocol, I'm declaring a delegate:

@property (nonatomic, weak) id <DateSelectViewControllerDelegate> delegate;

and in the implementation file, I synthesize the delegate, and I send a message to the delegate when the done button is pressed in my view:

- (IBAction)DonePressed:(id)sender {
    NSDate *chosen = [datePicker date];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

    [formatter setDateFormat:@"MM/dd/yyyy"];
    NSString *formatedDate = [formatter stringFromDate:chosen];

    //sending a message to the delegate
    [self.delegate dateSelectViewController:self theDate:formatedDate];

    [self.navigationController popViewControllerAnimated:YES];
}

In the .h file that's being delegated to, I'm importing the delegators .h file. And in the .m file I'm conforming to the protocol:

@interface MakePlantTVC ()<DateSelectViewControllerDelegate>
- (void)dateSelectViewController:(DateSelectViewController *)sender
                     theDate:(id)stringDate
{
    self.displayDate.text = stringDate;
    NSLog(@"delegate working");
}

For some reason the this is working at all. When the done button is pressed in my delegators class, the button does as it's supposed to and pops the view controller but it's like the message is never sent to the delegate. At first I thought I could be sending a message to nil but its' of type id, so that shouldn't be the case. Why is the message not being sent?

Hailei
  • 42,163
  • 6
  • 44
  • 69
Scott
  • 39
  • 2
  • 11
  • Try adding `NSLog(@"delegate = %@", self.delegate)` before sending the delegate a message. – zrslv Apr 25 '12 at 12:43
  • 1
    did u set the delegate ? – Roshit Apr 25 '12 at 12:43
  • while passing message to a delegate, its always nice to do a check for the availability of the delegate using this condition `if (self.delegate && [self.delegate respondsToSelector:@selector(method_name)]) { [self.delegate method_name]}` – Roshit Apr 25 '12 at 12:46
  • @zrxq I tried your advice and added that NSLog before and after sending the delegate a message and in both cases I receive null. I don't need to allocate a type id, do I? – Scott Apr 25 '12 at 12:51
  • You do. `id` is a pointer to an object. – zrslv Apr 25 '12 at 12:56
  • @zrxq I'm getting an error message when I try to alloc, init the delegate: self.delegate = [[id alloc] init]; The error message says receiver type id is not an objective-c class. – Scott Apr 25 '12 at 13:02
  • You have to alloc/init the implementation (`MakePlantTVC` in your case, I believe). – zrslv Apr 25 '12 at 13:06
  • the process is: first you set `alloc/init` then `setDelegate` but then somewhere you set another `alloc/init` for same class. If nothing helps look for second `alloc/init` – Nazir Oct 28 '13 at 19:10

1 Answers1

6

A few things came to mind

  • Have you set the delegate? It might sound stupid but when a delegate doesn't work it's because I forget or lose the IB connection, 90% of the time.
  • Does your weak object expire? A weak object is nil'ed - therefore you're performing a delegate operation on 'nothing' - perhaps you want something more retainy or an NSNotification

Other things I practice with delegates that might be useful

  • Use assert based programming? When you have a protocol with required functions, it's worth asserting, ie: NSAssert(delegate, @"Error, delegate not set!");
  • Check to see if the delegate responds to the selector
  • Dispatch delegate calls asynchronously with GCD, ie:

    dispatch_async(dispatch_get_main_queue(), ^{
      if ([delegate_ respondsToSelector:@selector(updateUI:)]) 
        [delegate_ updateUI:self];
    });
    

Hope this helps!

Matt Melton
  • 2,493
  • 19
  • 25
  • Hey matt, why is it important to dispatch delegate calls asynchronously with GCD? In my code I have something like: ` [self.delegate numberPadView:self digitPressed:[[[sender titleLabel] text] intValue]];` a required delegate method btw. I was curious about that, and how to implement the NSAssert message for my custom delegate method when I forget to implement the appropriate custom delegate methods. I'd like a fancy message to pop up when I forget to implement my own required delegate methods. – Pavan Feb 12 '14 at 00:56
  • It's likely that a delegate function will update the UI. Updating the UI should be done on the main thread. UI callbacks are guaranteed to occur on the main thread, but KVO, NSNotification and NSUrlConnection callbacks are not. A delegate target shouldn't care about its caller's thread politics. IMHO it's good practice to switch the main thread and let a delegate method implement it's own background switch if it requires it. By assuming delegates methods occur on the main thread you avoid implementing a test-switch-reinvoke in each of your delegate's public methods. – Matt Melton Feb 12 '14 at 09:51
  • RE fancy popup: implement `doesNotRecognizeSelector` – Matt Melton Feb 12 '14 at 09:53