转载

Objective-C:模拟按钮点击事件理解代理模式

OC中的协议(Protocol)和和.NET中的接口(Interface)类似,简单来讲,就是一系列方法的列表,其中声明的方法可以被任何类实现。不同的是,在.NET中,如果某个类实现了一个接口,就必须实现这个接口中声明的所有方法;但在OC中,可以不实现协议中声明的所有方法,需要用到某些功能,就去实现对应的方法即可。

这种模式一般称为 代理模式 。在iOS和OS X开发中,Apple采用了大量的代理模式来实现MVC中View(UI控件)和Controller(控制器)的 解耦

监听思想:如果想让某个对象能够监听某个控件的动作,就可以让这个对象实现特定的协议,好抽象~。说人话,比如,如果想要用户点击某个按钮后,APP能够做一些事情(例如返回到上一个界面),需要给按钮设置监听器监听按钮的点击事件,然后“返回上一个界面”这个事情就交给监听器去做。因为需要作出特定的响应,所以不是所有的对象都可以成为按钮的监听器的。那什么样的对象才能充当按钮的监听器呢?条件是:实现某个协议里的方法(这个协议一般在需要被监听的对象内部声明)。

以监听按钮的点击事件为例:

Objective-C:模拟按钮点击事件理解代理模式

Button:我可以被点,谁来监听我啊?

 //Button.h头文件 //和分类Catelogy一样,协议也可以写在其他文件中,但一般写在.h文件中 #import <Foundation/Foundation.h> @class Button; // <>代表实现某个协议 @protocol ButtonDelegate <NSObject>//协议也可以实现其他协议,定义的该协议实现了最根本的协议NSObject - (void)onClick:(Button *)btn;//这个方法是留给需要实现该协议的对象去调用 @end  @interface Button : NSObject @property (nonatomic, retain) id<ButtonDelegate> delegate;//按钮应提供一个属性来设置监听器,delegate就是按钮的监听器,不然按钮和其监听器无法通信  //不需要线程安全,故nonatomic;它是个对象,最好用retain;不知道声明类型的对象会成为自己的监听器,故id   - (void)click;//这个方法是按钮自己调用的,用来模拟点击按钮事件,调用该方法相当于点击了按钮  @end 
 //Button.m实现文件 #import "Button.h" @implementation Button - (void)dealloc {     [_delegate release];     [super dealloc]; } - (void)click {     // 如果_delegate实现了onClick:这个方法     if ( [_delegate respondsToSelector:@selector(onClick:)] ) {         // 按钮被点击了,就应该通知监听器.并且告诉监听器哪个按钮被点击了         [_delegate onClick:self];     } else {         NSLog(@"监听器并没有实现onClick:方法");     } } @end 

ButtonListerner:我想监听你呢!

 //ButtonListerner.h头文件 #import <Foundation/Foundation.h> // 对协议进行提前声明,跟@class的用途是一致的 @protocol ButtonDelegate; @interface ButtonListener : NSObject <ButtonDelegate>//要做Button的监听器,就要实现我Button定的协议 @end 
 //ButtonListerner.m实现文件 #import "ButtonListener.h" #import "Button.h"  @implementation ButtonListener - (void)onClick {//实现Button协议里为我准备的onClick方法     NSLog(@"ButtonListener已经监听到按钮被点击了"); } @end 

main:我来检查下,看ButtonListerner可不可以监听Button了。

 //main函数中实现对按钮的监听 #import <Foundation/Foundation.h> #import "Button.h" #import "ButtonListener.h"  int main(int argc, const char * argv[]) {     @autoreleasepool {         // 初始化一个按钮         Button *button = [[[Button alloc] init] autorelease];         // 初始化一个按钮的监听器         ButtonListener *listener = [[[ButtonListener alloc] init] autorelease];// 设置按钮的监听器         button.delegate = listener;         NSLog(@"button:%@", button);         // 点击按钮         [button click];     }     return 0; } 

main函数运行后打印的结果是:ButtonListener已经监听到按钮被点击了。

这表明ButtonListerner里的onClick方法被调用了,奇怪,在main函数中我们并没有调用这个方法呀。这就是我们想要的结果:当“[button click];”执行(前面说过,这表示Button被点击了),然后某些事情就自动处理了(比如这里ButtonListerner里的onClick方法)。再啰嗦几句吧。

理解这个监听过程,主要注意这两个方法:

  • - (void)click方法:这个方法是按钮自己实现的,相当于事件的发生;
  • - (void)onClick:方法:这个方法是代理去实现的。

上面的例子显示了当按钮Button调用自己的click方法时,跟着按钮的代理ButtonListener的onClick方法也被调用了,这样就达到了监听按钮点击事件的目的。也就是说,当我们想让一个按钮被点击后,其他地方能够进行一些各种各样的操作时,我们不需要在按钮内部去实现,在它的代理对象内部去实现就可以啦,这不就达到了 解耦 的目的嘛。

协议也可以写在一个新建的协议文件里,并且实现该协议的对象可以对该协议里的方法选择性地去实现 。哪些方法是必须实现的,哪些方法又是可以选择性实现的呢?这取决于该方法是如何被声明的。

定义两个协议:

//StudyDelegate.h 协议文件
#import <Foundation/Foundation.h>  @protocol StudyDelegate <NSObject> // 默认就是@required - (void)test3;  // @required表示必须实现的方法 // 虽然字面上说是必须实现,但是编译器并不强求某个类进行实现 @required - (void)test;  - (void)test1;  // @optional表示可选(可实现/也可不实现) @optional - (void)test2; @end
 //LearnDelegate.h协议文件 #import <Foundation/Foundation.h>  @protocol LearnDelegate <NSObject>  @end 

定义一个学生类,该类的对象用来实现上面的协议:

 //Student.h #import <Foundation/Foundation.h> @protocol StudyDelegate, LearnDelegate;  @interface Student : NSObject <Study, Learn>  @end 
 //Student.m #import "Student.h" #import "StudyDelegate.h" #import "LearnDelegate.h"  @implementation Student  @end 

判断Student类型的对象是否实现了协议:

 #import <Foundation/Foundation.h> #import "Student.h"  @protocol StudyDelegate;  int main(int argc, const char * argv[]) {      @autoreleasepool {         Student *stu = [[[Student alloc] init] autorelease];                  // 注意:OC是弱语法的,对类型要求不严格         // NSString *stu = [[[Student alloc] init] autorelease];         // [stu stringByAbbreviatingWithTildeInPath];                  // conformsToProtocol:判断是否遵守了某个协议         if ([stu conformsToProtocol:@protocol(StudyDelegate)]) {             NSLog(@"Student遵守了StudyDelegate这个协议");         }                  // respondsToSelector:判断是否实现了某个方法         if ( ![stu respondsToSelector:@selector(test)] ) {             NSLog(@"Student没有实现test这个方法");         }     }     return 0; } 

运行结果是:Student遵守了StudyDelegate这个协议;Student没有实现test这个方法;验证了刚才的说法:可以遵守协议,但不实现该协议里声明的方法。遵守协议即实现协议。

注意, selector就相当于方法(消息),发送消息就是调用方法

原文  http://www.cnblogs.com/yif1991/p/5065349.html
正文到此结束
Loading...