Как расширить протоколы / делегаты в Objective-C - PullRequest
72 голосов
/ 09 апреля 2009

Если я хочу расширить класс, такой как AVAudioPlayer, каков наилучший способ добавить еще один метод в AVAudioPlayerDelegate? Я делаю категорию для этого, я расширяю это? Если я расширю его, то мне также нужно будет обязательно перезаписать фактический делегат getter / setter? Как бы я продлил протокол? Следующее дает мне ошибки



@protocol AudioTrackDelegate : AVAudioPlayerDelegate {
    - (void)foo;
}
@end

@interface AudioTrack : AVAudioPlayer {
}
@end

Ответы [ 2 ]

130 голосов
/ 09 апреля 2009

Синтаксис для создания протокола, который реализует другой протокол, таков:

@protocol NewProtocol <OldProtocol>
- (void)foo;
@end

Если вы хотите вызвать метод в NewProtocol для указателя, напечатанного как OldProtocol, вы можете вызвать respondsToSelector:

if ([object respondsToSelector:@selector(foo)])
    [(id)object foo];

Или определите методы-заглушки как категорию в NSObject:

@interface NSObject (NewProtocol)
- (void)foo;
@end
@implementation NSObject (NewProtocol)
- (void)foo
{
}
@end
11 голосов
/ 09 апреля 2009

Помните, что протокол не добавляет код в скомпилированное приложение - он только усиливает тот факт, что ваш класс должен реализовывать методы, которые считаются "соответствующими" протоколу. Хорошим примером этого будет создание группы классов с одинаковым способом работы: <printable> или <serialized> и т. Д. Таким образом, вы можете создать протокол <plays>, например:

@protocol plays
    - (void) play;
    - (NSString *) type;
@end

И затем класс, соответствующий <plays>, ДОЛЖЕН реализовывать методы play и type. Если это не так, компилятор выдает предупреждение, но в любом случае компилирует класс. В своем коде вы проверяете, соответствует ли объект протоколу со следующим кодом:

if ([obj conformsTo: @protocol(plays)]) {
    [obj play];
}

Категория фактически добавляет новые методы динамически в ваш класс. Эти методы доступны глобально для среды выполнения как селекторы и могут вызываться по имени, как в @selector(foo) и [object foo:bar];

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

В вашем случае, может быть, в отдельном файле AVAudioPlayerDelegate_TrackOps.m

#import "AVAudioPlayerDelegate.h"
@implementation AVAudioPlayerDelegate (TrackOps)

- (NSObject *) foo {
    // do foo stuff;
    return bar;
}

@end

Если указать категорию NSObject, все классы ответят на foo. Foo может быть автономным методом Objc_perform_selector(@selector(foo)).

Итог: используйте категорию, чтобы добавить быстрый метод в класс, протоколы для обеспечения выполнения реализации методов и подклассы для специализации существующих классов (такие как добавление переменных-членов или новые важные функции). Категории также могут использоваться для переопределения метода или двух, когда подкласс не нужен и не нужен, но обычно, если вы хотите добавить функциональность в класс, вы создаете подкласс. Для большего количества примеров, идей и другой общей информации по этой теме всегда есть введение Apple в Objective-C

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...