1、代理简介:代理就是委托别的对象为自己做事情,首先此对象要给别的对象发送消息,即调用别的对象中的成员方法,别的对象根据此对象发送的消息处理后返回一个处理结果给此对象即消息反馈。
2、代理类的执行过程
(1)一般情况下:一个类委托别的类为自己做事情,是直接将代理类的对象作为自身成员(直接用@property为其设置set/get方法),然后在自己的成员方法中直接调用代理类的成员方法进行实现。
(2)这种做法的弊端是:耦合性太强。只能绑定一个代理类,一旦要再使用别的代理类就必须要对类中的代理类声明@property等许多地方进行修改,如果想让同一个类的多个对象同时绑定多个代理类进行实现是不可能的事情。
3、协议代理模式进行解决
利用协议和万能指针解决问题:利用协议的代理设计模式进行解决,具体方法是:并不在当前类中声明具体代理类的对象,先为当前类要绑定的所有代理类新建一个协议并在协议中声明代理类的要做的事情(方法声明列表),然后在当前类的@property属性中声明一个万能指针id类型的变量,限制这个变量保存的代理类对象必须遵守新建的代理类协议,有两种方式进行实现具体如下:
@property(nonatomic,strong) NSObject<代理类协议> *变量
或者用第二种如下格式进行声明
@property(nonatomic,strong) id<代理类协议> 变量
然后再创建遵守代理类协议的多个代理类,在外部直接调用此类对象的点语法对保存代理类对象的id类型变量进行赋值即可绑定代理类,格式如下:此类对象.id类型的变量=遵守代理类协议的代理类对象
然后此类对象调用自身成员方法就可以间接调用绑定代理类对象中的成员方法进行实现了。
此模式的好处是:可以绑定多个代理类而不用修改定义此类的代码。
(注意:代理类协议要遵守基协议即NSObject协议,因为id类型的变量跟具体类的对象指针不同,具体的代理类最终都继承了NSObject根类,所以具体代理类的对象都从根类继承了NSObject基协议的所有方法,因此具体代理类的对象调用任何继承根类的方法都不会报错。而id类型的变量不同,它仅仅告诉编译器此变量能代替任何对象指针,你给它提供了哪些协议去遵守,编译器就认为此id类型的变量能调用哪些协议中的方法。如果想用该变量调用release根类方法对此变量保存的对象进行释放就要在它遵守的代理类协议中有根类的方法即基协议中的对应方法,所以让限制此变量保存对象的代理类协议遵守基协议NSObject即可)
4、protocol代理模式的步骤归纳:
第一步:新建遵守了基协议的代理类协议。
第二步:为用来保存代理对象且遵守代理类协议的id变量提供set、get方法。在当前类的类声明中利用“@property id<代理协议> 变量”的方式进行set/get方法的自动生成。
第三步:新建遵守代理类协议的代理类。在代理类的.m文件中实现协议中的方法。
第四步:在当前类(老板类)的成员方法中调用代理类方法。即在当前类的一些成员方法中利用已声明的id变量或Xcode自动提供的”_id变量”来调用代理协议中的方法去进行执行。
第五步:重写当前类的dealloc方法。在(当前类)老板类中重写dealloc方法,并在方法内用id变量调用release方法对id变量所保存的代理类对象进行释放。(即遵守谁创建,谁释放的原则)。
第六步:绑定代理类对象。新建当前类对象与要绑定的代理类对象;并为当前类对象调用set方法来绑定代理类对象,即如下格式:
“当前类对象.id变量=代理类对象;”然后调用自身成员方法即可实现,即[当前类对象 自身成员方法];便可。
代码验证如下:
新建代理类协议
新建TicketDelegate.h编辑如下:
//
// TickerDelegate.h
// Protocol_Design
//
// Created by apple on 15/8/18.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
//声明代理类办委托类做事情的一些方法
@protocol TickerDelegate <NSObject>//建议任何协议都要遵守基协议,以便id调用基类方法
//返回票价
-(double)ticketPrice;
//还剩多少张票
-(int)leftTicketsNumber;
@end
新建委托类Person
新建Person.h编辑如下:
//
// Person.h
// Protocol_Design
//
// Created by apple on 15/8/18.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "TickerDelegate.h"
@interface Person : NSObject
-(void)buyTicket; //委托代理类的自身成员方法
//拥有一个代理属性
//id代表任意的代理类
//但id变量保存对象的代理类必须遵守TicketDelegate协议
@property (nonatomic,retain) id<TickerDelegate> delegate;
/*与下列语句等效
@property(nonatomic,retain) NSObject<TickerDelegate> *delegate;*/
@end
编辑Person.m如下:
//
// Person.m
// Protocol_Design
//
// Created by apple on 15/8/18.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import "Person.h"
@implementation Person
-(void)buyTicket {
double price = [_delegate ticketPrice];//如果在声明id变量时不加协议限制,编译器是不知道id类型变量_delegate有这些方法的
int number=[_delegate leftTicketsNumber];
NSLog(@"通过代理的帮忙,票价 =%f 票数=%d",price,number);
}
-(void)dealloc{
[_delegate release];/*如果id变量绑定的代理协议不遵守基协议的话,编译器是不会知道id变量_delegate有基类中的这些方法的(例如:release或retain之类的基类方法)*/
[super dealloc];
}
@end
新建第一个代理类Agent
编辑Agent.h如下:
//
// Agent.h
// Protocol_Design
//
// Created by apple on 15/8/18.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "TickerDelegate.h"
@interface Agent : NSObject<TickerDelegate>
@end
编辑Agent.m如下:
//
// Agent.m
// Protocol_Design
//
// Created by apple on 15/8/18.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import "Agent.h"
@implementation Agent
//票的价格
-(double)ticketPrice
{
// ... 亲自跑电影院\或者打电话
return 1000;
}
//剩余的票数
-(int)leftTicketsNumber
{
// ... 亲自跑电影院\或者打电话
return 1;
}
@end
新建第二个代理类NextAgent
编辑NextAgent.h如下:
//
// NextAgent.h
// Protocol_Design
//
// Created by apple on 15/8/18.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "TickerDelegate.h"
@interface NextAgent : NSObject<TickerDelegate>
@end
编辑NextAgent.m如下:
//
// NextAgent.m
// Protocol_Design
//
// Created by apple on 15/8/18.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import "NextAgent.h"
@implementation NextAgent
//票的价格
-(double)ticketPrice
{
// ... 亲自跑电影院\或者打电话
return 500;
}
//剩余的票数
-(int)leftTicketsNumber
{
// ... 亲自跑电影院\或者打电话
return 10;
}
@end
在main.m中调用如下:
//
// main.m
// Protocol_Design
//
// Created by apple on 15/8/18.
// Copyright (c) 2015年 liu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Agent.h"
#import "NextAgent.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
Person *p=[[[Person alloc] init] autorelease];
Agent *a=[[[Agent alloc] init] autorelease];
NextAgent *na=[[[NextAgent alloc] init] autorelease];
p.delegate=a; //让a来做自己的代理
[p buyTicket];
p.delegate=na;//让na来做自己的代理
[p buyTicket];
}
return 0;
}
运行结果如下:
常用于手机界面中为布局绑定数据源: