How to extend protocols / delegates in Objective-C?

If i want to extend a class like AVAudioPlayer, whats the best way to also add another method to AVAudioPlayerDelegate?

Should I make a category for it, do I extend it?

If I extend it do I then also have to make sure to overwrite the actual delegate getter/setter? How would I extend the protocol?

The following gives me errors

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

@interface AudioTrack : AVAudioPlayer {
}
@end

Solution 1:

The syntax for creating a protocol that implements another protocol is as such:

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

If you want to call a method in NewProtocol on a pointer typed as OldProtocol you can either call respondsToSelector:

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

Or define stub methods as a category on NSObject:

@interface NSObject (NewProtocol)
- (void)foo;
@end
@implementation NSObject (NewProtocol)
- (void)foo
{
}
@end

Solution 2:

Remember a protocol adds no code to the compiled app -- it only enforces the fact that your class must implement the methods to be considered "conforming" to the protocol. A good use of this would be to generate a group of classes with all the same way of operating: <printable> or <serialized>, etc. So you could create a <plays> protocol for instance:

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

And then a class that conforms to <plays> MUST implement the play and type methods. If it doesn't, the compiler issues a warning but compiles the class anyway. In your code you check if an object does conform to a protocol with the following code:

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

A category actually adds new methods dynamically to your class. These methods are globally accessible to the runtime as selectors and can be called by name as in @selector(foo) and [object foo:bar];

The purpose of a category is to add special new code to a class even if you don't have the source code for that class. There may be security problems and you could create memory leaks in classes, etc.

In your case maybe, in a separate file AVAudioPlayerDelegate_TrackOps.m

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

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

@end

Putting it as a category of NSObject makes all classes respond to foo. Foo can be a stand alone method Objc_perform_selector(@selector(foo)) as well.

Bottom Line: use a category to add a quick method to a class, protocols for enforcing method implementations, and subclasses to specialize existing classes (things like adding member variables or major new functionality). Categories can also be used to override a method or two when a subclass is not needed and wanted, but usually if you want to add functionality to a class you make a subclass. For more examples, ideas, other general information on this topic, there's always the Apple introduction to Objective-C