iOS中delegate、protocol的关系
分类: iOS Development2014-02-12 10:47 277人阅读 评论(0) 收藏 举报
delegateiosprocotolcategoryobject-c
刚开始接触iOS,对delegate、protocol这两个概念比较模糊。参考了一些资料,记录下来体会。
1.protocol
protocol和interface的概念类似,是object-c语法的一部分。protocol就是一系列不属于任何类的方法的列表。其中声明的方法能被任何类实现。只在protocol中定义行为,在不同的情况下使用不同的实现。这种模式一般称为代理模式。在iOS和OS X开发中,Apple采用了大量的代理模式来实现MVC中View和Controller的解耦。
如何定义protocol呢?
在声明文件(h文件)中通过关键字@protocol定义,然后给出Protocol的名称,方法列表,然后用@end表示Protocol结束。在@end指令结束之前定义的方法,都属于这个Protocol。
@protocol myProtocol <NSObject> @required - (int)add:(int) a and:(int)b; @optional - (int)minus:(int)a and:(int)b; @end
这里还有两个关键字,@required和@optional,一个是必须实现的,一个是可选的。可以根据名字直接判断。
如何使用这个protocol呢?
@interface text : NSObject<myProtocol> @end
定义一个类来使用protocol,用尖括号(<...>)括起来的就是我们定义的protocol,如果要采用多个Protocol,可以在尖括号内引入多个Protocol名称,并用逗号隔开即可。
在这个类的实现文件中来实现方法:
@implementation text - (int)add:(int)a and:(int)b{ return a + b; } - (int)minus:(int)a and:(int)b{ if (a >= b) { return a - b; } else return b - a; } @end
iOS中Protocol和Java语言中的interface很类似,如果一些类之间没有继承关系,但是又具备某些相同的行为,则可以使用Protocol来描述它们的关系。不同的类,可以遵守同一个Protocol,在不同的场景下注入不同的实例,实现不同的功能。Cocoa框架中大量采用了这种模式实现数据和UI的分离。例如UIView产生的所有事件,都是通过委托的方式交给Controller完成。根据约定,框架中后缀为Delegate的都是Protocol,例如UIApplicationDelegate,UIWebViewDelegate等。
2.delegate
delegate和protocol没什么关系,Delegate本身应该称为一种设计模式。是把一个类自己需要做的一部分事情,让另一个类(也可以就是自己本身)来完成。在执行一个类的方法的时候,想在这个方法里面跳到另外一个类执行另外一个类的方法,就可以把delegate设置为另外一个类。
举个例子:如果我在工作的时候想知道某场nba比赛的结果和喜欢的球星的数据,但是我在工作,不可以干与工作无关的事情,我可以选择发消息给两个人,让他们查一下结果告诉我,一个去查比赛结果,一个去查喜欢球星的数据,然后我继续工作。等过了一会,这两个人查到想要的东西,把结果返回给我(通知我)。那么这两个人就是我的不同的委托对象。我.delegate = 某人。
如何使用delegate:用上面描述的例子来开始:
先定义一个 代理类 person1 person.h如下:
#import <UIKit/UIKit.h> @protocol queryDelegate <NSObject> - (NSString *)query; @end @interface Person1 : UIViewController<queryDelegate> @end
person.m
- (NSString *)query{ NSString * result = [NSString stringWithFormat:@"热火赢太阳:103比98"]; return result; }
首先定义了协议与方法,代理类person1遵循这个协议,并且实现了委托方法。
同样定义一个代理类person2,person2.h
#import <UIKit/UIKit.h> #import "Person1.h" @interface Person2 : UIViewController<queryDelegate> @end
person2.m
- (NSString *)query{ NSString * data =[NSString stringWithFormat:@"詹姆斯的数据是37分9篮板3助攻" ]; return data; }
代理类person2同样遵循某个协议,并且实现了委托方法。
我们在界面上添加两个button和 label,要求点击上面的button,会在它下面的label上显示今天nba 热火vs太阳的比赛结果。点击下面的button的时候,会在下面的lable显示今天比赛的詹姆斯的数据;
添加完界面,给两个button 设置action 给两个label设置 outlet,ok,设置好之后,界面如下:
delegateViewController.h:
#import <UIKit/UIKit.h> #import "Person1.h" #import "Person2.h" @interface delegateViewController : UIViewController @property (weak,nonatomic) id<queryDelegate> delegate;//声明delegate - (IBAction)button1Action:(id)sender; - (IBAction)button2Action:(id)sender; @property (weak, nonatomic) IBOutlet UILabel *labelResult; @property (weak, nonatomic) IBOutlet UILabel *labelData; @end
下面看delegateViewController.m:
#import "delegateViewController.h" @interface delegateViewController () @end @implementation delegateViewController @synthesize labelData; @synthesize labelResult; ..... - (IBAction)button1Action:(id)sender { Person1 *pe1 = [[Person1 alloc] init]; self.delegate = pe1;//设置代理对象为person1 NSString * result = [self.delegate query];//通过委托变量调用委托方法 [labelResult setText:result]; } - (IBAction)button2Action:(id)sender { Person2 *pe2 = [[Person2 alloc]init]; self.delegate = pe2;//设置代理对象为person2 NSString* data = [self.delegate query] //通过委托变量调用委托方法 [labelData setText:data]; }
这一步主要做的是声明委托变量,设置代理,并且通过委托变量调用委托的方法。
执行结果:
delegate概念的作用:
先看书上给出的经典说法:
1.The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.
委托的主要价值是让你可以在一个核心对象里定制多个对象的功能特性。
2.构建helper object 的工具 Helper Object are commonly used to add functionality to an existing class without having to subclass it.
构建helper object,helper object用来对已有的类添加功能特性而不是通过子类继承实现。
下面转载一篇个人认为对delegate比较经典的解释,原文地址:点击打开链接
Delegate本身应该称为一种设计模式。是把一个类自己需要做的一部分事情,让另一个类(也可以就是自己本身)来完成。
比如ClassC
@interface ClassC { id delegate; } @end
首先定义一个id类型的变量,名字叫做delegate。那么ClassC的实现(.m文件)里就可以用delegate这个变量了。当然这里完全可以用其它名字而不是delegate。
我们也可以这样写:
@interface ClassC { ClassB *delegate; } @end
这样我们知道了delegate是一个ClassB,它就可以提供ClassB里的方法。可以把一部分ClassC里的工作放在ClassB里去实现。这样的写法看起来是不是有点奇怪?或者应该写成这样?
@interface ClassC { ClassB *classB; } @end
.......按照上面这样写,delegate就没有了。
所以说其实delegate只是一种模式,大家约定俗成,当把自己内部一部分实现暴露给另外一个类去做的时候,就叫实际做事的类为delegate。
为什么会需要把内部实现提出来给另一个类做呢?最常见的目的就是为了在隐藏实现的前提下,提供一个自定义的机会。比如Apple提供的iOS SDK里就有众多的delegate,比如最常用的UITableView,我们没法知道Apple怎么重用UITableViewCell,怎么处理UITableView里Cell的增加、删减,因为我们没有源码。但是我们可以通过实现Delegate的方法来控制一个UITableView的一些行为。UITableViewDataSource其实和delegate是一样一样的,只是由于意义不同换了个名字罢了。
protocol在此扮演了什么角色呢?
protocol是一种语法,它提供了一个很方便的、实现delegate模式的机会。
比如写UITableView的时候,Apple这么干
UITableView.m:
- (void)doSomething { [self blahblah]; [self.delegate guruguru];//放到delegate中去执行这个guruguru函数 [self blahblah]; }
delegate是我们写的类,这个类如果可以被传给UITableView做为其delegate,那唯一要求,就是它实现了
- (void)guruguru;
这个方法。
如果我们把这个方法定义在一个protocol里
@protocol XXXProtocol - (void)guruguru; @end
就说明了,UITableView需要的delegate是一个conform to XXXProtocol的类。这就正好是id<XXXProtocol>表达的意思。
无论具体的类是什么,它还有其它什么方法,只要它conform to这个protocol,就说明它可以被传给UITableView,作为它的delegate。那么Apple为了让我们知道这个protocol是delegate需要conform的protocol,它就把XXXProtocol改成了UITableViewDelegate。
这样我们看到protocol的名字里有Delegate,就知道这个protocol里的函数是用来做自定义(Customization)的了。
delegate是对别的对象指针,按MVC一般最好赋值对象是Controller,它实现的是一种模式,它本身不是模式。Protocal是一组方法的定义。当id<protocal>定义为delegate时,就是要用别的对象即赋值的delegate去实现protocal里的方法,这个过程使用的模式就是代理模式。Delegate类+protocal的话就保证了你另外实现的delegate类里面必须有这个委托方法,但至于delegate类还可以干其他事情。
转iOS中delegate、protocol的关系,布布扣,bubuko.com