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

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



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

@interface AudioTrack : AVAudioPlayer {
}
@end

Ответ 1

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

@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

Ответ 2

Помните, что протокол не добавляет код в скомпилированное приложение - он только подтверждает тот факт, что ваш класс должен реализовать методы, которые считаются "соответствующими" протоколу. Хорошим использованием этого было бы создание группы классов со всем тем же способом: <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)).

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