Метод делегата кажется @required, где он объявлен как @Optional

Я создал свой собственный делегат для класса 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 (неопознанный селектор отправлен в экземпляр). Как селектор может отсутствовать, если он необязателен?

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


person Wolfgang Schreurs    schedule 30.01.2010    source источник


Ответы (2)


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

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

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

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

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

а не просто:

[delegate didAddMessage:theMessage];

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

person mipadi    schedule 30.01.2010
comment
Спасибо, сообщение [respondsToSelector:] устранило мою проблему. Немного странно, что такое сообщение требуется, когда сами сообщения объявлены как @Optional. - person Wolfgang Schreurs; 30.01.2010
comment
Подумайте об этом: если метод является необязательным, возможно, класс делегата не реализовал его. Если вы отправляете сообщение, на которое делегат не отвечает, вы получите сбой (по умолчанию). - person mipadi; 30.01.2010
comment
@необязательный просто означает, что класс, который говорит, что он выполняет протокол, не требуется для реализации этого метода. То, что вас смущает — вызывающая сторона проверяет [respondsToSelector:] — это то, как работает обмен сообщениями all делегата. - person Jon Reid; 30.01.2010
comment
Мне нравится этот ответ больше, потому что он отвечает более подробно - person Heavy_Bullets; 18.10.2013
comment
Меня расстраивает, что Objective C изо всех сил старается поступать правильно, если вы вызываете метод для указателя NULL, но когда вы вызываете метод, который вы специально указали как необязательный, происходит сбой! - person Andrew; 06.02.2014