1:代理:代理是一种通用的设计模式,由三部分组成:
协议:用来指定代理双方可以做什么,必须做什么;
代理:根据指定的协议,完成委托方需要实现的功能
委托:根据指定的协议指定代理去完成什么功能
如果没有协议的实现
Person.h
#import <Foundation/Foundation.h>
#import "Agent.h"
@interface Person : NSObject
//拥有一个代理属性
@property(nonatomic,retain)Agent *delegate;
-(void)buyTicket;
@end
Person.m
#import "Person.h"
@implementation Person
-(void)buyTicket{
int left= [_delegate leftTicketNumber];
double price =[_delegate ticketPrice];
NSLog(@"剩余票数是 %d 每张票的价钱是%f",left,price);
}
@end
Agent.h#import <Foundation/Foundation.h>
@interface Agent : NSObject
-(int)leftTicketNumber;
-(double)ticketPrice;
@end
Agent.m#import "Agent.h"
@implementation Agent
-(int)leftTicketNumber{
return 2;
}
-(double)ticketPrice
{
return 1000;
}
@end
main.m #import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person =[[Person alloc]init];
Agent *agent =[[Agent alloc]init];
person.delegate=agent;
[person buyTicket];
}
return 0;
}
如果我们不想用Agent 代理而是要用NextAgent的话,我们就需要将Agent代理换成NextAgent代理,这样存在的问题就是代码的耦合性太强,所有我们需要将代码的类型换成id类型
@property(nonatomic,retain)id*delegate;
但是运行编译会报错,因为delegate的类型是id类型,所以不知道代理里面有哪些方法,无法发送消息,所以代码[_delegate lefTicketNumber] 会报错;这个时候就可以将代理的方法放在协议里面去,只要你使用代理必须遵守这个协议,遵守这个协议代理就知道有哪些方法,就可以发送消息;所以代码如下:
#import <Foundation/Foundation.h>
//创建一个TicketDelegate 协议,声明Agent里面的方法
@protocol TicketDelegate <NSObject>
-(int)leftTicketNumber;
-(double)ticketPrice;
@end
Person.h 里面导入进去协议并在id 类型后遵守TicketDelegate协议
#import <Foundation/Foundation.h>
#import "TicketDelegate.h"
//因为有其他类的声明,所以使用<@class 类名>来声明该类,只需要知道有这个类,不需要关心里面有哪些方法,所以使用该声明,而无需导入#import “Agent”,无需拷贝Agent类里面的所有实现方法
/*
<@class 类名>和 #import “类名”的区别
1:@class做一个简单的声明,并不包含类的方法声明,成员变量声明,只是告诉编译器在哪个.h文件中
#import 是将整个类的所有声明都拷贝一份,包含被引用类的所有信息,包括引用类的变量和方法
2:#import 不能嵌套包含,但是@class 能实现相互引用:A有个属性参照B,B有个属性参照A
3:使用@class 方式由于需要知道被引用类的名称就可以,在实现类需要用到被引用类中实体变量和方法,所以在.m中需要使用#import 来包含引用类的头文件
4:如果有上百个头文件都#import了同一个文件,或者这些文件依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率太差,所以使用@class方式是最快捷效率最高的做法
*/
@class Agent;
@interface Person : NSObject
//拥有一个代理属性
//代理的类名随便,但是必须遵守TicketDelegate协议
@property(nonatomic,retain)id<TicketDelegate>delegate;
-(void)buyTicket;
运行结果:
在iOS中代理的本质就是代理对象内存的传递和操作,我们在委托类设置代理对象后,实际上只是用一个id类型的指针将代理对象进行了一个弱引用,委托方让代理方执行操作,实际上是在委托类中向这个id 类型指针指向的对象发送消息,而这个id 类型指针指向的对象,就是代理对象
代理原理
根据上面的图像得知:委托方的代理属性本质上就是代理对象自身,设置委托代理就是代理属性指针指向代理对象,相当于代理对象只是在委托方中调用自己的方法,如果方法没有实现就会导致崩溃。