Как мне создать делегатов в Objective-C?

Я вижу, что ответ Oracle по-прежнему отсутствует, поэтому вот он:

SQL> with yourTable as
  2  ( select 1 yourColumn from dual union all
  3    select 2 from dual union all
  4    select 4 from dual union all
  5    select 8 from dual
  6  )
  7  select EXP(SUM(LN(yourColumn))) As ColumnProduct from yourTable
  8  /

COLUMNPRODUCT
-------------
           64

1 row selected.

С уважением, Роб.

728
задан Wayne Chen 12 May 2017 в 17:12
поделиться

3 ответа

Делегат Objective C является объектом, который был присвоен delegate свойство другой объект. Для создания один Вы просто определяете класс, который реализует методы делегата, Вы интересуетесь и отмечаете тот класс как реализацию протокола делегата.

, Например, предположите, что Вы имеете UIWebView. Если требуется реализовать его делегата webViewDidStartLoad: метод, Вы могли бы создать класс как это:

@interface MyClass<UIWebViewDelegate>
// ...
@end

@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView { 
    // ... 
}
@end

Тогда Вы могли создать экземпляр MyClass и назначить его делегатом веб-представления:

MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;

На UIWebView сторона, это, вероятно, имеет код, подобный этому, чтобы видеть, отвечает ли делегат webViewDidStartLoad: сообщение с помощью [1 129] respondsToSelector: , и отправьте его при необходимости.

if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
    [self.delegate webViewDidStartLoad:self];
}

само свойство делегата обычно объявляется weak (в ARC), или assign (предварительный ARC) для предотвращения сохраняют циклы, так как делегат объекта часто держит сильную ссылку к тому объекту. (Например, контроллер представления часто является делегатом представления, которое он содержит.)

Делегаты Создания к Вашим Классам

Для определения собственных делегатов необходимо будет объявить их методы где-нибудь, как обсуждено в Документы Apple о протоколах . Вы обычно объявляете формальный протокол. Объявление, перефразируемое от UIWebView.h, было бы похоже на это:

@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end

Это походит на интерфейсный или абстрактный базовый класс, поскольку он создает специальный тип для Вашего делегата, UIWebViewDelegate в этом случае. Конструкторы делегата должны были бы принять этот протокол:

@interface MyClass <UIWebViewDelegate>
// ...
@end

И затем реализуют методы в протоколе. Для методов, объявленных в протоколе как [1 116] (как большинство методов делегата), необходимо свериться -respondsToSelector: прежде, чем назвать конкретный метод на нем.

Именование

Методы делегата обычно называют, начиная с имени класса делегирования и берут объект делегирования в качестве первого параметра. Они также часто используют желание - должен - или сделал - форма. Так, webViewDidStartLoad: (первый параметр является веб-представлением), а не loadStarted (берущий параметры), например.

Оптимизация Скорости

Вместо того, чтобы проверить, отвечает ли делегат на селектор каждый раз, когда мы хотим передать его, можно кэшировать ту информацию, когда делегаты установлены. Один очень очевидный способ, чтобы сделать это должно использовать битовое поле, следующим образом:

@protocol SomethingDelegate <NSObject>
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end

@interface Something : NSObject
@property (nonatomic, weak) id <SomethingDelegate> delegate;
@end

@implementation Something {
  struct {
    unsigned int didFinishLoadingItem:1;
    unsigned int didFailWithError:1;
  } delegateRespondsTo;
}
@synthesize delegate;

- (void)setDelegate:(id <SomethingDelegate>)aDelegate {
  if (delegate != aDelegate) {
    delegate = aDelegate;

    delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
    delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
  }
}
@end

Затем в теле, мы можем проверить, что наш делегат обрабатывает сообщения путем доступа к нашему delegateRespondsTo структура, а не путем отправки -respondsToSelector: много раз.

Неофициальные Делегаты

Перед протоколами существовали, было распространено использовать категория на [1 122] для объявления методов, которые мог реализовать делегат. Например, CALayer все еще делает это:

@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end

Это по существу говорит компилятору, что любой объект мог бы реализовать displayLayer:.

Вы тогда использовали бы тот же -respondsToSelector: подход, как описано выше для вызова этого метода. Делегаты просто реализуют этот метод и присваиваются delegate свойство, и вот именно (нет никакого объявления, что Вы соответствуете протоколу). Эта методика является общепринятой в библиотеках Apple, но новый код должен использовать более современный подход протокола выше, так как этот подход загрязняет NSObject (который делает автоматическое заполнение менее полезным), и мешает компилятору предупреждать Вас об опечатках и подобных ошибках.

877
ответ дан Jesse Rusak 13 May 2017 в 03:12
поделиться

Возможно, это больше вроде того, что Вы пропускаете:

, Если Вы происходите из C++ как точка зрения, делегаты берут немного привыкающее к - но в основном 'они просто работают'.

способ, которым это работает, состоит в том, что Вы устанавливаете некоторый объект, который Вы записали как делегат в NSWindow, но Ваш объект только имеет реализации (методы) для одного или нескольких из многих возможных методов делегата. Таким образом, что-то происходит, и NSWindow хочет назвать Ваш объект - он просто использует Цель-c's respondsToSelector метод, чтобы определить, хочет ли Ваш объект тот метод, названный, и затем называет его. Это - то, как объективные-c работы - методы ищутся по требованию.

Это полностью тривиально, чтобы сделать это с Вашими собственными объектами, нет ничего специального продолжения, Вы могли, например, иметь NSArray из 27 объектов, все различные виды объектов, только 18 некоторые из них имеющий метод -(void)setToBue;, другие 9 не делают. Таким образом для вызова setToBlue на всех из 18, которым нужен в сделанный, что-то вроде этого:

for (id anObject in myArray)
{
  if ([anObject respondsToSelector:@selector(@"setToBlue")])
     [anObject setToBlue]; 
}

другая вещь о делегатах состоит в том, что они не сохраняются, таким образом, всегда необходимо устанавливать делегата в nil в Вашем MyClass dealloc метод.

17
ответ дан dandan78 13 May 2017 в 03:12
поделиться

При использовании метода формального протокола для создания поддержки делегатов я обнаружил, что можно обеспечить надлежащую проверку типов (хотя и во время выполнения, а не во время компиляции), добавив что-то вроде:

if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
    [NSException raise:@"MyDelegate Exception"
                format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}

в код аксессора делегата (setDelegate). Это помогает минимизировать ошибки.

18
ответ дан 22 November 2019 в 21:30
поделиться