zoukankan      html  css  js  c++  java
  • ObjectiveC学习之路 委托模式

    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. int main (int argc, const char * argv[]) {   
    4.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];  
    5.     Screen *screen=[[Screen alloc] init];   
    6.     screenscreen.delegate=screen;   
    7.     [screen onTouch];   
    8.     [screen release];   
    9.     [pool drain];   
    10.     return 0;   

    这里先不用管:

    1. screenscreen.delegate=screen; 

    后面再说。

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

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

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

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

    1. #import <Foundation/Foundation.h>   
    2. #import "Action.h"  
    3. @interface Screen : 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. @implementation Screen  
    3. @synthesize delegate;  
    4. - (void) onTouch{   
    5.     NSLog(@"on touch …");   
    6.     if ([delegate conformsToProtocol:@protocol(Action)] &&   
    7.         [delegate respondsToSelector:@selector(doAction)]) {   
    8.         [delegate performSelector:@selector(doAction)];   
    9.     }   
    10.     NSLog(@"on touched.");   
    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. int main (int argc, const char * argv[]) {   
    4.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];  
    5.     Screen *screen=[[MyScreen alloc] init];  
    6.     [screen onTouch];   
    7.     [screen release];   
    8.     [pool drain];   
    9.     return 0;   

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

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

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

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

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

    实现文件:

    1. #import "Screen.h"  
    2. @implementation Screen  
    3. @synthesize delegate;  
    4. - (void) onTouch{   
    5.     NSLog(@"on touch …");   
    6.     if ([delegate conformsToProtocol:@protocol(Action)] &&   
    7.         [delegate respondsToSelector:@selector(doAction)]) {   
    8.         [delegate performSelector:@selector(doAction)];   
    9.     }   
    10.     NSLog(@"on touched.");   
    11. }  
    12. @end 

    这里不再实现doAction方法。

    下面看MyScreen类的头文件:

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

    MyScreen类的实现文件:

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

    用类别实现委托模式

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

    main方法:

    1. int main (int argc, const char * argv[]) {   
    2.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];  
    3.  
    4.     Screen *screen=[[Screen alloc] init];  
    5.     [screen onTouch];   
    6.     [screen release];    
    7.     [pool drain];   
    8.     return 0;   

    Screen类的头文件:

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

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

    实现文件:

    1. #import "Screen.h"  
    2. @implementation Screen  
    3. @synthesize delegate;  
    4. - (id) init{   
    5.     if (self=[super init]) {   
    6.         delegate=self;   
    7.     }   
    8.     return self;   
    9. }  
    10. - (void) onTouch{   
    11.     NSLog(@"on touch …");   
    12.     if ([delegate respondsToSelector:@selector(doAction)]) {   
    13.         [delegate performSelector:@selector(doAction)];   
    14.     }   
    15.     NSLog(@"on touched.");   
    16. }  
    17. @end  

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

    1. 2011-05-26 10:37:30.843 DelegateDemo[5853:a0f] on touch …   
    2. 2011-05-26 10:37:30.846 DelegateDemo[5853:a0f] on touched. 

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

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

    实现文件:

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

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

    1. 2011-05-26 10:37:30.843 DelegateDemo[5853:a0f] on touch …   
    2. 2011-05-26 10:37:30.846 DelegateDemo[5853:a0f] BANG!!!!!!   
    3. 2011-05-26 10:37:30.846 DelegateDemo[5853:a0f] on touched. 

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

  • 相关阅读:
    coredump分析
    Sword LRU算法
    C++ STL迭代器失效问题
    Sword DB主从一致性的解决方法
    Sword CRC算法原理
    C语言 按位异或实现加法
    Linux 等待信号(sigsuspend)
    C语言 宏定义之可变参数
    Linux shell字符串操作
    C++ *和&
  • 原文地址:https://www.cnblogs.com/xgbzsc/p/2507237.html
Copyright © 2011-2022 走看看