1、委托模式从GoF装饰(Decorator)模式、适配器(Adapter)模式和模板方法(Template Method)模式等演变而来。不只是Cocoa Touch框架,在Cocoa框架中,委托模式也得到了广泛的应用。
2、委托是为了降低一个对象的复杂度和耦合度,使其能够更具通用性而将其中一些处理置于委托对象中的编码方式。通用类因为通用性(与具体应用的无关性)而变为框架类,框架类保持委托对象的指针,并在特定时刻向委托对象发送消息。消息可能只是通知委托对象做一些事情,也可能是对委托对象进行控制。
3、举例说明。
假设有一个哲学家,他要做三件事:“吃饭”、“睡觉”和“工作”。为了提高效率,他会找一个徒弟,把事情委托给徒弟做。然后要成为他的徒弟,需要遵守一个协议,协议规定了要能够处理好上述三件事。结合上图三者关系如下:
从图可知,通用类(philosopher)保持指向委托对象(ViewController)的“弱引用”(id<PhilosopherDelegate> delegate),委托对象(ViewController)是哲学家的“徒弟”,它实现了协议PhilosopherDelegate。PhilosopherDelegate规定了3个方法:-(void)sleep、-(void)eat和-(void)work方法。
PhilosopherDelegate.h代码如下:
1 @PRotocol PhilosopherDelegate 2 3 @required 4 -(void) sleep; 5 -(void) eat; 6 -(void) work; 7 8 @end
可以看到,委托协议philosopherDelegate定义了3个方法。如果该委托协议没有.m文件,它的定义可以放在别的.h文件中。它的实现类就是委托类ViewController,代码如下:
1 // 2 //ViewController.h 3 // 4 5 @interface ViewController : UIViewController<PhilosopherDelegate> @end 6 // 7 //ViewController.m 8 // 9 @implementation ViewController 10 11 - (void)viewDidLoad 12 { 13 [super viewDidLoad]; 14 Philosopher *obj = [[Philosopher alloc ] init]; 15 obj.delegate = self; 16 [obj start]; 17 } 18 19 #pragma -- PhilosopherDelegate方法实现 20 -(void) sleep 21 { 22 NSLog(@"sleep..."); 23 } 24 25 -(void) eat 26 { 27 NSLog(@"eat..."); 28 } 29 30 -(void) work 31 { 32 NSLog(@"work..."); 33 } 34 35 @end
委托对象如何与通用类建立引用关系呢?我们通过viewDidLoad方法中的obj.delegate = self语句来指定委托对象和通用类间的引用关系。一般情况下,通用类由框架直接提供。在这个例子中,我们根据需要自己实现了通用类Philosopher。Philosopher.h的代码如下:
1 // 2 //Philosopher.h 3 //DelegatePattern 4 // 5 #import "PhilosopherDelegate.h" 6 @interface Philosopher : NSObject 7 { 8 NSTimer *timer; 9 int count; 10 } 11 @property (nonatomic, weak) id<PhilosopherDelegate> delegate; 12 -(void) start; 13 -(void) handle; 14 @end
在上述代码中,我们定义了delegate属性,它的类型是id<PhilosopherDelegate>,它可以保存委托对象的引用,其中属性weak说明是”弱引用“。这里使用弱引用方式是为了防止内存引用计数增加而导致委托对象无法释放的问题。Philosopher.m的代码如下:
1 // 2 //Philosopher.m 3 //DelegatePattern 4 5 #import "Philosopher.h" 6 @implementation Philosopher 7 @synthesize delegate; 8 9 -(void) start 10 { 11 count= 0; 12 timer = [NSTimer scheduledTimerWithTimeInterval:3.0 13 target:self selector:@selector(handle)userInfo:nil repeats:YES]; 14 } 15 16 -(void)handle 17 { 18 switch (count) 19 { 20 case 0: 21 [self.delegate sleep]; 22 count++; 23 break; 24 case 1: 25 [self.delegate eat]; 26 count++; 27 break; 28 case 2: 29 [self.delegate work]; 30 [timer invalidate]; 31 break; 32 } 33 } 34 @end
在本例中,Philosopher模拟一些通用类发出调用,这个调用通过NSTimer每3秒发出一个,依次向委托对象发出消息sleep、eat和work。self.delegate是指向委托对象ViewController的指针,[self.delegate sleep]是调用ViewController中的sleep方法。
总结一下它们各自的”职责“:
1、通用类(哲学家):保持向委托对象的弱引用, 1 @property (nonatomic, weak) id<PhilosopherDelegate> delegate; ;向委托对象发送消息 [self.delegate sleep];
2、委托协议:定义通用类需要实现的方法 1 -(void) sleep;
3、委托对象(徒弟):实现/遵守协议 1 @interface ViewController : UIViewController<PhilosopherDelegate>; ;与通用类建立引用关系 1 Philosopher *obj = [[Philosopher alloc ] init]; 2 obj.delegate = self; ;实现协议方法
1 -(void) sleep 2 { 3 NSLog(@"sleep..."); 4 }
资料:《iOS开发指南》