delegate(代理)是OC中的一种模式,可以用来传递值和配置值(这里我们只讨论传值的过程)。设想有两个界面,其中一个界面要改变另一个界面的数据,这里我们就会用到代理模式,将改变数据的那个界面作为被改变界面的代理,通过代理来返回给后者被改变的数据。
房屋中介
设想我们现在需要去租房子,我们需要一个中介,这个中介就是一个代理,他去帮我们完成我们的需求。现在我们来实现这个场景。
//中介Agent.h
#import <Foundation/Foundation.h>
@protocol RentHouseDelegate <NSObject>
-(void)rentHouseDidFinished:(NSString *)result;//默认是required的
@end
@interface Agent : NSObject
@property (nonatomic,assign) id<RentHouseDelegate>delegate
-(void)renthouse:(NSString *)result;//Agent类需要实现的方法
@end
//中介Agent.m
#import "Agent.h"
@implementation Agent
-(void)renthouse:(NSString *)result{
if([self.delegate respondsToSelector:@selector(rentHouseDidFinished:)]){
[self.delegate rentHouseDidFinished:result];
}//调用被代理类对象实现的协议中的方法用来返回数据
}
@end
首先我们将中介作为代理,首先就要定义一个协议,这个协议用来约束被代理类的行为,如果不做协议的话,就需要为每一个被代理类书写他们自己的接受返回数据的方法,那样就太冗杂了。对于协议名也是有要求的,一般就是代理类所做的操作的英文描述加上delegate并且每个单词的首字母都要大写。协议中声明的被代理类必须要实现的方法就是当代理类(中介)做完相关操作后如何返回给被代理类的方法。紧接着,我们在代理类的类声明中,声明了一个属相变量delegate我们用这个变量来记录是哪个被代理类的对象委托代理进行操作。注意到这个变量是assign的,这样做是为了防止循环引用的出现而导致内存管理出错,但不一定每个都写成assign,有些情况下写成strong也行的。delegate的修饰词是:id<RentHouseDelegate>,id修饰词说明这个变量现在是不知道什么类型的,只有等运行起来才知道,<RentHouseDelegate>说明这个变量只能记录那些遵守了此协议的被代理类的对象。接下来我们真正声明了一个Agent类该做的工作--renthouse。
在代理类的实现文件中,我们实现了Agent类的renthouse方法,我们首先检查了当前被代理类中是否实现了rentHouseDidFinished方法,只有实现了,我们才会去进行相关操作。
//Person.h
#import <Foundation/Foundation.h>
#import "Agent.h"
@interface Person : NSObject<RentHouseDelegate>
-(void)needHouse;//需要找房子了
@end
现在我们有人要去租房子了,所以我们声明了一个person类,在租房子时,我们需要中介的帮助,所以我们选择遵守Agent的协议,并且声明了person类自己的方法。
//Person.m
#import "Person.h"
#import "Agent.h"
@implementation Person
-(void)needhouse{
//1.首先我们要找到一个中介
Agent * xw = [Agent new];
//2.然后我们告诉中介被代理人是谁
xw.delegate = self;
//3.最后我们让中介带着我们的需求去找房子
[xw renthouse:@"三室两厅"];
}
-(void)rentHouseDidFinished:(NSString *)result{
NSLog(@"找到了,是%@",result);
}
@end
在person类的实现中,我们首先实现了自己类中声明的方法,注意第二步是十分重要的一步,如果缺少了这一步,代理就不知道我们的委托人是谁,最后返回数据时,就不知改将数据返回给谁。最后我们实现了协议中声明的方法,这个是必须要实现的,不只是因为它是默认required的,还因为我们需要通过代理调用这个方法来改变原始数据,所以这个方法必须实现。
//main.m中
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Cat.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person * jack = [Person new];
[jack needHouse];
}
return 0;
}
代理步骤总结
1.首先确定代理类,在其中定义协议
2.在代理类的类声明中声明一个用于记录遵守了协议的被代理类对象的属性变量。
3.在被代理类(需要代理回调给他数据的类)中,告诉代理类回调的数据传给谁。因为被代理类可能是一个控制器,有多个视图,所以可以通过 self.控件对象.delegate = 数据传给的对象 来回传数据(赋值号左边必须是已经定义了的delegate)。这是非常重要的一步,同时也非常容易遗忘,如果忘了,被代理类就接收不到数据,所以就不会进行相应的行为。
4.在被代理类实现文件中实现代理类协议中声明的方法。