Метод делегата, по-видимому, является обязательным, если он объявлен как @optional - PullRequest
4 голосов
/ 30 января 2010

Я создал свой собственный Делегат для класса ObjC. Сам класс имеет дело с операциями Core Data. Методы делегатов используются для информирования других классов об изменениях, произошедших с хранилищем данных. Класс, который имеет дело с хранилищем данных, называется Datastore, а его делегат называется DatastoreDelegate. Мой UIViewController (ContactsViewController) реализует делегат.

Мой DatastoreDelegate объявлен следующим образом:

@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

Странно то, что мой код прекрасно работал с этими методами, за исключением метода [didAddMessage:]. Всякий раз, когда я пытаюсь вызвать этого делегата из класса Datastore, я получаю сообщение об ошибке от ContactsViewController. Ошибка говорит мне, что селектор [didAddMessage:] отсутствует в экземпляре ContactsViewController (нераспознанный селектор отправлен в экземпляр). Как может отсутствовать селектор, если он необязательный?

Я должен отметить, что мой класс Datastore - Singleton. Я не уверен, связано ли это как-то с этой проблемой.

Ответы [ 2 ]

24 голосов
/ 30 января 2010

«Необязательно» означает, что вызывающий абонент отвечает за проверку того, что цель отвечает на данный селектор. E.g.:

if ([_myDelegate respondsToSelector:@selector(didAddMessage:)])
{
    [_myDelegate didAddMessage:theMessage];
}
4 голосов
/ 30 января 2010

Вы внедрили didAddMessage: в свой ContactsViewController? Это необязательно, поэтому вы не обязаны его реализовывать, но если вы отправите сообщение didAddMessage: на ContactsViewController, но на самом деле не внедрили его в ContactsViewController, вы все равно получите предупреждение компилятора. Другими словами, @optional просто означает, что вам не нужно реализовывать его, но компилятор все равно может выдать предупреждение, если вы его не реализовали, но попытаетесь использовать его.

То, что вы можете сделать в Datastore, это:

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

, а не просто:

[delegate didAddMessage:theMessage];

(Вы все равно получите предупреждение компилятора в первом примере, но его можно игнорировать, поскольку вы проверяете во время выполнения, чтобы убедиться, что соответствующий метод реализован в делегате.)

...