Objective-C学习之路 委托模式

Objective-C学习之路 委托模式


Objective-C学习之路 委托模式是本文要介绍内容,委托模式很重要,比如官方交互API,委托模式使用的很常见,比如UIView的setAnimationDelegate,设置动画的委托。不理解委托模式,就不能很快的理解很多API的使用,因为它们使用一样的模式,了解这个模式,就会心领神会,立即上手。

下面用通俗的话说说委托模式是干什么用的。实际上Objective-C中的委托模式,类似于Java中的回调(CallBack)机制,或者说监听器机制。再或者说,类似JavaScript语言里面的onclick事件和函数的作用。比如要实现点击一个按钮之后做什么事情,这里肯定有个视图类,有个控制类,无论你是使用什么语言和开发工具。视图类能知道用户什么时候点击了按钮,但是不知道点击了以后做什么,控制类知道点击按钮后做什么,而不知道何时用户会点击。那么,可以将控制类委托给视图类,当点击的时候视图类调用控制类。

如果使用过Java的Swing等做本地图形界面开发,应该知道在视图类中包含了大量的(匿名)内部类,或者要注册监听器,这些机制起到和Objective-C委托类似的功效。可以这样理解:监听器、(匿名)内部类是实现怎么做的部分,但是不知道何时会发生事情,视图类在事件发送时调用监听器、(匿名)内部类,视图类是知道何时发生事情的。

写个简单的示例,是在main方法里写的,模拟一下委托在视图和控制中的作用。这里面,我有一个屏幕(Screen)类,就把它当视图吧。需求是当点击屏幕的时候爆炸。那么我有个动作(Action)类,它会实现爆炸动作。

用协议实现委托模式

下面的代码写的很生硬,后面会逐渐演化为合理的实现。第一个示例只是想说明技术上如何实现,没有实际运用上的意义。

这里因为是模拟,可以把main方法看作是用户再操作界面,通过点击创建了个视图(Screen),然后调用Screen的实例方法onTouch,这里模拟用户用手点击了屏幕:

 
   
  1. #import<Foundation/Foundation.h>
  2. #import"Screen.h"
  3. intmain(intargc,constchar*argv[]){
  4. NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];
  5. Screen*screen=[[Screenalloc]init];
  6. screenscreen.delegate=screen;
  7. [screenonTouch];
  8. [screenrelease];
  9. [pooldrain];
  10. return0;
  11. }

这里先不用管:

 
   
  1. screenscreen.delegate=screen;

后面再说。

Action类,在这里用协议来实现:

 
   
  1. #import<Cocoa/Cocoa.h>
  2. @protocolAction<NSObject>
  3. -(void)doAction;
  4. @end

是一个协议,该协议继承了NSObject协议。这里要注意,NSObject在这里不是类,确实有同名类。这个协议定义了一个doAction方法,这个方法可实现比如“屏幕爆炸”的需求。

下面说说屏幕(Screen)类,头文件:

 
   
  1. #import<Foundation/Foundation.h>
  2. #import"Action.h"
  3. @interfaceScreen:NSObject<Action>{
  4. id<Action>delegate;
  5. }
  6. @property(nonatomic,retain)id<Action>delegate;
  7. -(void)onTouch;
  8. @end

这里的onTouch方法,就是模拟Screen被用户点击后调用的方法。Screen类实现了Action协议。然后它还有个Action类型的成员delegate。为了能设置delegate实例变量,还为它设置了property。

下面看看实现文件:

 
   
  1. #import"Screen.h"
  2. @implementationScreen
  3. @synthesizedelegate;
  4. -(void)onTouch{
  5. NSLog(@"ontouch…");
  6. if([delegateconformsToProtocol:@protocol(Action)]&&
  7. [delegaterespondsToSelector:@selector(doAction)]){
  8. [delegateperformSelector:@selector(doAction)];
  9. }
  10. NSLog(@"ontouched.");
  11. }
  12. -(void)doAction{
  13. NSLog(@"Bang!!!!!!!!!");
  14. }
  15. @end

这里重点看onTouch方法内部代码,要判断delegate是否是Action协议,而且是否有doAction方法,这个判断够严谨了。如果正确,就调用Action协议的doAction方法。

实际上未必要让Screen实现Action协议,虽然开发中经常是类似这样的做法。任意的实现Action协议的类实例都可以设置给screen的delegate属性。

上面的示例和开发中碰到的情况不很像,实际情况往往类似下面示例的样子。首先看看main方法:

 
   
  1. #import<Foundation/Foundation.h>
  2. #import"MyScreen.h"
  3. intmain(intargc,constchar*argv[]){
  4. NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];
  5. Screen*screen=[[MyScreenalloc]init];
  6. [screenonTouch];
  7. [screenrelease];
  8. [pooldrain];
  9. return0;
  10. }

这里发现增加了个MyScreen 类。它继承自Screen类。这里的代码不再设置delegate属性,因为已经在MyScreen类的init方法中设置了。后面会看到。

Action协议没有变化,只是增加了optional:

 
   
  1. #import<Cocoa/Cocoa.h>
  2. @protocolAction<NSObject>
  3. @optional
  4. -(void)doAction;
  5. @end

Screen类,可以看作抽象类,它主要供继承使用,来复用委托模式的代码。头文件:

 
   
  1. #import<Foundation/Foundation.h>
  2. #import"Action.h"
  3. @interfaceScreen:NSObject<Action>{
  4. id<Action>delegate;
  5. }
  6. @property(nonatomic,retain)id<Action>delegate;
  7. -(void)onTouch;
  8. @end

实现文件:

 
   
  1. #import"Screen.h"
  2. @implementationScreen
  3. @synthesizedelegate;
  4. -(void)onTouch{
  5. NSLog(@"ontouch…");
  6. if([delegateconformsToProtocol:@protocol(Action)]&&
  7. [delegaterespondsToSelector:@selector(doAction)]){
  8. [delegateperformSelector:@selector(doAction)];
  9. }
  10. NSLog(@"ontouched.");
  11. }
  12. @end

这里不再实现doAction方法。

下面看MyScreen类的头文件:

 
   
  1. #import<Cocoa/Cocoa.h>
  2. #import"Screen.h"
  3. @interfaceMyScreen:Screen{
  4. }
  5. @end

MyScreen类的实现文件:

 
   
  1. #import"MyScreen.h"
  2. @implementationMyScreen
  3. -(id)init{
  4. if(self=[superinit]){
  5. delegate=self;
  6. }
  7. returnself;
  8. }
  9. -(void)doAction{
  10. NSLog(@"Bang!!!!!!!!!");
  11. }
  12. @end

用类别实现委托模式

可以使用类别(Category)实现委托模式。还是上面的例子。下面使用Category实现了个示例。

main方法:

 
   
  1. intmain(intargc,constchar*argv[]){
  2. NSAutoreleasePool*pool=[[NSAutoreleasePoolalloc]init];
  3. Screen*screen=[[Screenalloc]init];
  4. [screenonTouch];
  5. [screenrelease];
  6. [pooldrain];
  7. return0;
  8. }

Screen类的头文件:

 
   
  1. #import<Foundation/Foundation.h>
  2. @interfaceScreen:NSObject{
  3. iddelegate;
  4. }
  5. @property(nonatomic,retain)iddelegate;
  6. -(void)onTouch;
  7. @end

在这个示例中,实际上property没有起什么作用。

实现文件:

 
   
  1. #import"Screen.h"
  2. @implementationScreen
  3. @synthesizedelegate;
  4. -(id)init{
  5. if(self=[superinit]){
  6. delegate=self;
  7. }
  8. returnself;
  9. }
  10. -(void)onTouch{
  11. NSLog(@"ontouch…");
  12. if([delegaterespondsToSelector:@selector(doAction)]){
  13. [delegateperformSelector:@selector(doAction)];
  14. }
  15. NSLog(@"ontouched.");
  16. }
  17. @end

写到这里,如果运行代码,只会打印类似下面的日志:

 
   
  1. 2011-05-2610:37:30.843DelegateDemo[5853:a0f]ontouch…
  2. 2011-05-2610:37:30.846DelegateDemo[5853:a0f]ontouched.

下面写Category代码,名称为ScreenAction,它的头文件:

 
   
  1. #import<Cocoa/Cocoa.h>
  2. #import"Screen.h"
  3. @interfaceScreen(ScreenAction)
  4. -(void)doAction;
  5. @end

实现文件:

 
   
  1. #import"ScreenAction.h"
  2. @implementationScreen(ScreenAction)
  3. -(void)doAction{
  4. NSLog(@"BANG!!!!!!");
  5. }
  6. @end

实现了这部分代码再执行:

 
   
  1. 2011-05-2610:37:30.843DelegateDemo[5853:a0f]ontouch…
  2. 2011-05-2610:37:30.846DelegateDemo[5853:a0f]BANG!!!!!!
  3. 2011-05-2610:37:30.846DelegateDemo[5853:a0f]ontouched.

小结:Objective-C学习之路 委托模式的内容介绍完了,希望本文对你有所帮助。

<!--leftbotcon end-->
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值