如何在Objective-C中扩展协议/委托

diz*_*izy 72 iphone objective-c

如果我想扩展像AVAudioPlayer这样的类,那么最好的方法是向AVAudioPlayerDelegate添加另一个方法吗?我是否为它做了一个类别,我是否扩展它?如果我扩展它,那么我还必须确保覆盖实际的委托getter/setter吗?我该如何扩展协议?以下是我的错误



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

@interface AudioTrack : AVAudioPlayer {
}
@end
Run Code Online (Sandbox Code Playgroud)

rpe*_*ich 130

创建实现其他协议的协议的语法如下:

@protocol NewProtocol <OldProtocol>
- (void)foo;
@end
Run Code Online (Sandbox Code Playgroud)

如果你想调用一个NewProtocol键入指针的方法,OldProtocol你可以调用respondsToSelector:

if ([object respondsToSelector:@selector(foo)])
    [(id)object foo];
Run Code Online (Sandbox Code Playgroud)

或者将存根方法定义为以下类别NSObject:

@interface NSObject (NewProtocol)
- (void)foo;
@end
@implementation NSObject (NewProtocol)
- (void)foo
{
}
@end
Run Code Online (Sandbox Code Playgroud)

  • 协议没有方法,它有方法定义; 也就是说,它描述了一个类必须被视为"符合"所述协议的名称,参数和返回类型.通过你的评论/问题,我打赌你忘记在你的-setDelegate中调用[super setDelegate:value]: (10认同)

小智 11

请记住,协议不会向已编译的应用程序添加任何代码 - 它只会强制您的类必须实现被视为"符合"协议的方法.很好地利用它可以生成一组具有相同操作方式的类:<printable>或者<serialized>等等.所以你可以创建一个<plays>协议,例如:

@protocol plays
    - (void) play;
    - (NSString *) type;
@end
Run Code Online (Sandbox Code Playgroud)

然后一个符合<plays>MUST 的类必须实现playtype方法.如果没有,编译器会发出警告,但无论如何都会编译该类.在您的代码中,使用以下代码检查对象是否符合协议:

if ([obj conformsTo: @protocol(plays)]) {
    [obj play];
}
Run Code Online (Sandbox Code Playgroud)

类别实际上会为您的类动态添加新方法.运行时可以将这些方法作为选择器全局访问,并且可以通过名称调用,如@selector(foo)[object foo:bar];

类别的目的是为类添加特殊的新代码,即使您没有该类的源代码也是如此.可能存在安全问题,您可能会在类等中创建内存泄漏.

在您的情况下,也许在一个单独的文件中 AVAudioPlayerDelegate_TrackOps.m

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

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

@end
Run Code Online (Sandbox Code Playgroud)

将它作为一个类别NSObject使所有类都响应foo.Foo也可以是一个独立的方法 Objc_perform_selector(@selector(foo)).

底线:使用类别向类添加快速方法,使用强制方法实现的协议,使用子类来专门化现有类(如添加成员变量或主要新功能).当不需要和需要子类时,类别也可用于覆盖一个或两个方法,但通常如果要为类创建子类添加功能.有关此主题的更多示例,想法和其他一般信息,Apple总是引入Objective-C