我们来用delegate 的想法来实作前面提到的状况。
定义Protocol 与Delegate 的方式
我们先来建立一个NSButton
的subclass,叫做MyButton
,MyButton
的delegate必须实现MyButtonDelegate
这个protocol。.h文件中定义如下:
#import <Cocoa/Cocoa.h>
@class MyButton;
@protocol MyButtonDelegate
- (void)myButtonDidBecomeClicked:(MyButton *)button;
- (void)myButtonDidBecomeDoubleClicked:(MyButton *)button;
- (void)myButtonDidBecomeTripleClicked:(MyButton *)button;
- (void)myButtonDidBecomeQuadrupleClicked:(MyButton *)button;
@end
@interface MyButton : NSButton
{
id <MyButtonDelegate> delegate;
}
@property (weak, nonatomic) id <MyButtonDelegate> delegate;
@end
逐行解释这个header 里头的内容:
#import <Cocoa/Cocoa.h>
:因为NSButton 是在AppKit 里头,所以我们必须调用的header。@class MyButton;
:因为在我们接下来的protocol定义中,会用到MyButton
这个class,但是MyButton
其实是定义在MyButtonDelegate
的下面,所以我们需要先预先定义MyButton
这个class的存在。- 从
@protocol MyButtonDelegate
开始,就是在定义MyButtonDelegate
这个protocol里头的四个method。接下来定义MyButton
这个class,里头有一个叫做delegate的变数。
实现Delegate Methods
假如我们有一个叫做MyController
的controller实例,要成为MyButton
的delegate,我们会这么做。首先是.h部分:
@interface MyController : NSObject <MyButtonDelegate>
{
IBOutlet MyButton *myButton;
}
@end
我们要先定义MyController
有实现MyButtonDelegate
这个protocol,如此一来,假如MyController
漏了实现哪些定义在MyButtonDelegate
里头的method,在编译的时候就会跳出警告,要求我们修正,如果我们还是不实现的话,执行时,就会发生找不到selector对应的实现的错误而crash。
如果MyController
又同时是其他实例的delegate的话,我们可以在这段用尖括号包起来,继续加入其他的protocol的名称,例如<MyButtonDelegate, AnotherProtocol>
。至于一个实例是否有遵守某个protocol,我们可以用conformsToProtocol:
检查。
在MyController
的实作中,我们就只要将myButton
的delegate设成自己,然后实作该实作的method。我个人不太喜欢在protocol的宣告中出现大量注解,因为在实作protocol的时候,最方便的方式就是直接把protocol定义的method复制贴上,接着逐一把肉放进protocol定义的骨干里;如果当中出现注解,复制贴上之后,还要把这些注解删掉,其实很烦人。
@implementation MyController
- (void)awakeFromNib
{
[myButton setDelegate:self];
}
#pragma mark - MyButtonDelegate
- (void)myButtonDidBecomeClicked:(MyButton *)button
{
}
- (void)myButtonDidBecomeDoubleClicked:(MyButton *)button
{
}
- (void)myButtonDidBecomeTripleClicked:(MyButton *)button
{
}
- (void)myButtonDidBecomeQuadrupleClicked:(MyButton *)button
{
}
@end
我们在这边透过setDelegate:
指定delegate,如果我们把delegate宣告成是一个IBOutlet的话,也可以直接在Interface Builder中连结。
Delegate Methods 是怎么被调用的?
MyButton
是怎样调用delegate 的呢?其实很简单。
@implementation MyButton
- (void)mouseDown:(NSEvent *)theEvent
{
switch ([theEvent clickCount]) {
case 1:
[delegate myButtonDidBecomeClicked:self];
break;
case 2:
[delegate myButtonDidBecomeDoubleClicked:self];
break;
case 3:
[delegate myButtonDidBecomeTripleClicked:self];
break;
case 4:
[delegate myButtonDidBecomeQuadrupleClicked:self];
break;
default:
break;
}
}
@synthesize delegate;
@end