views:

89

answers:

2

I've created my own Delegate for a ObjC class. The class itself deals with Core Data operations. Delegate methods are used to inform other classes about changes that happened to the datastore. The class that deals with the datastore is called Datastore and it's delegate is called DatastoreDelegate. A UIViewController of mine (ContactsViewController) implements the delegate.

My DatastoreDelegate is declared as followed:

@class Datastore;
@protocol DatastoreDelegate <NSObject>;
@optional
- (void)didAddMessage:(Message *)message;
- (void)didUpdateContact:(Contact *)contact;
- (void)didAddContact:(Contact *)contact;
- (void)didUpdateContact:(Contact *)contact;
- (void)didDeleteContacts;
@end

The weird thing is, my code all worked fine with these methods except for the [didAddMessage:] method. Whenever I try to call this delegate from within the Datastore class I get an error from the ContactsViewController. The error tells me the [didAddMessage:] selector is missing in the ContactsViewController instance (Unrecognized selector sent to instance). How can the selector be missing if it's optional?

I should note that my Datastore class is a Singleton. I'm not sure if this is somehow related to this issue I'm having.

+1  A: 

"Optional" means the caller is responsible for checking that a target responds to a given selector. E.g.:

if ([_myDelegate respondsToSelector:@selector(didAddMessage:)])
{
    [_myDelegate didAddMessage:theMessage];
}
Darren
A: 

Did you implement didAddMessage: in your ContactsViewController? It's optional so you aren't forced to implement it, but if you send the didAddMessage: message to ContactsViewController but haven't actually implemented it in ContactsViewController, you'll still get a compiler warning. In other words, @optional just means you don't have to implement it, but the compiler may still give a warning if you haven't implemented it but try to use it.

What you might want to do in Datastore is this:

if ([delegate respondsToSelector:@selector(didAddMessage:)]) {
    [delegate didAddMessage:theMessage];
}

rather than just:

[delegate didAddMessage:theMessage];

(You'll still get a compiler warning in the first example, but it's safe to ignore since you're checking at runtime to see if the appropriate method is implemented in the delegate.)

mipadi
Thanks, the [respondsToSelector:] message fixed my issue. Kind of weird that such a message is required when the messages themselves are declared as @optional.
Wolfgang Schreurs
Think about it: if the method is optional, then the delegate class may not have implemented it. If you send a message to which the delegate does not respond, then you'll get a crash (by default).
mipadi
@optional simply means that a class that says it fulfills a protocol is not required to implement that method. The thing that confuses you — the caller checking [respondsToSelector:] — is the way *all* delegate messaging works.
Jon Reid