协议的应用—代理设计模式

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;

运行结果:


2:代理实现流程

    在iOS中代理的本质就是代理对象内存的传递和操作,我们在委托类设置代理对象后,实际上只是用一个id类型的指针将代理对象进行了一个弱引用,委托方让代理方执行操作,实际上是在委托类中向这个id 类型指针指向的对象发送消息,而这个id 类型指针指向的对象,就是代理对象

                                                     代理原理

根据上面的图像得知:委托方的代理属性本质上就是代理对象自身,设置委托代理就是代理属性指针指向代理对象,相当于代理对象只是在委托方中调用自己的方法,如果方法没有实现就会导致崩溃。

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值