前言
最初接触到Delegate,是页面之间的传递数据,也就是网上出现的大部分页面传值教程,即:A页面跳转B页面,B跳回A时需要传递一些数据,这时我理解的Delegate仅限于页面传值;后来常常封装一些东西时,也常用Delegate来传递消息和值,这时理解的Delegate是NSObject之间的消息传递者,但是却越来越看不懂Delegate了,联想到UITableView的Delegate和Datasource,一直有疑问,系统是如何得到并使用我们设置的section个数,cell样式来显示Table样式的呢,它扮演了什么角色?
代理,本意是代替某对象去完成某种业务,如果仅仅是去完成消息提醒或者传递数据是不是大材小用了!!??正好有点时间,我好好的研究了一下,发现了Delegate的更多的作用,这里跟大家分享一下,希望能够帮助新人更好的理解和掌握Delegate的使用。
一、没有代理的情况
首先我们在没有代理的情况下,我们如何完成一些业务呢?
下面我用一些生活的例子,通俗的讲解一下Delegate的使用;
业务一:我想去买一些水果
突然有一天,我心血来潮的想吃点水果,便找到附近的水果店去买些水果。
这里有两个对象,我和水果店,钱和水果是两者的业务关系
首先定义一下我和水果店对象:
接着我们来定义水果店售卖水果店业务
.h 文件
#import
#import
@interface FruitShop : NSObject
@property (assign,nonatomic) CGFloat applePrice; // 苹果价格
// 卖水果业务
-(CGFloat)saleFruitWithMoney:(NSInteger)money;
@end
.m 文件
// 实现卖水果业务
-(CGFloat)saleFruitWithMoney:(NSInteger)money{
self.applePrice = 6.8; // 水果6块8一斤
CGFloat number = money / self.applePrice ; // 称斤计算
return number; // 算好返回
}
接着,我们来实现我买水果的业务:
@interface MyObject : NSObject
/**
买水果
*/
-(void)buySomeFruits;
@end
我去水果店完成买水果业务
#import "MyObject.h"
#import "FruitShop.h" //
@implementation MyObject
// 实现买水果业务
-(void)buySomeFruits{
FruitShop *shop = [FruitShop new]; // 获取到水果店对象
CGFloat number = [shop saleFruitWithMoney:50]; // 掏出50块钱买苹果
NSLog(@"50元可以卖到%.2f斤苹果",number);
}
@end
在Controller里导入我这个对象,完成买水果事情
MyObject *my = [MyObject new];
[my buySomeFruits];
运行结果:
结论:在没有代理的情况下,买水果这样的业务,我需要亲自实现该业务,并且需要获取水果店对象,调用其卖水果的方法得到结果。
这是正常的业务逻辑,接下来我们使用代理来完成这项业务。
二、有代理的情况
在没有代理的情况下,我想买一些水果,必须亲自去水果店里去完成这项事务,福州这样的天气,热的要死,来回一趟像是体验了一回桑拿房,我可不可以让别人来帮我去买呢?我只负责取回水果就好了,这不是爽歪歪?
这时候我们就需要代理了,并且需要赋给他买水果的能力
首先我们来新建代理的协议,我理解为Java中的接口,只有方法声明,没有实现
我们将购买水果的能力分离出来赋予代理
#import
@protocol MyDelegate
// 我们将买水果的能力抛出来(并且钱一并交出,不然你的代理会被打死的)
-(CGFloat)buySomeFruitsWithMoney:(NSInteger)money;
@end
接着我们将该代理声明为我的代理者,表示这是我的代理者了,我买水果的事物就交给他去完成了
#import "MyDelegate.h"
@interface MyObject : NSObject
@property(weak,nonatomic)id MyDelegate;
@end
这时候,我再想买水果时,就可以交给我的代理去完成了
声明我想买水果,此时我的.h文件就成了这样
#import
#import "MyDelegate.h"
@interface MyObject : NSObject
@property(weak,nonatomic)id MyDelegate;
// 我想去买水果
-(void)wantToBuySomeFruits;
@end
#import "MyObject.h"
@implementation MyObject
-(void)wantToBuySomeFruits{
// 将该事物交给我的代理去做
// 我的代理有所指向,可以找到响应该需求的店铺,并该业务被实现了
if (self.MyDelegate&&[self.MyDelegate respondsToSelector:@selector(buySomeFruitsWithMoney:)]) {
CGFloat number = [self.MyDelegate buySomeFruitsWithMoney:50]; // 我的代理去完成买水果的业务
NSLog(@"我的代理者为我买回了%.2f斤水果",number); // 我拿到了我的水果,开心的吃了起来
}
}
@end
到这里,我的代理并不能完成买水果的业务,因为,我的代理并不只知道去哪里买水果,并且也不知道能不能完成买水果业务(接下来我们需要完成水果店卖水果的业务)
这时水果店A知道了我有买苹果的需求,便接受了我的代理,响应并实现了我的需求
#import
#import "MyDelegate.h"
// 上一个例子的水果店在这里变成了父类,我新建了其子类,表示水果店A
@interface FruitShop : NSObject// 接受了我的代理
@property (assign,nonatomic) CGFloat applePrice; // 苹果价格
@end
@interface A_FruitShop : FruitShop
@end
在水果店A的实现类中完成代理协议买水果的能力
@implementation A_FruitShop
// A店表示可以满足我的需求,并实现了买水果的业务
-(CGFloat)buySomeFruitsWithMoney:(NSInteger)money{
self.applePrice = 9.8; // A水果店苹果9块8一斤
CGFloat number = money / self.applePrice ; // 称斤计算
return number; // 算好返回
}
@end
这样,我们在Controller里来执行
MyObject *my = [MyObject new];
A_FruitShop *A_Shop = [A_FruitShop new];
my.MyDelegate = A_Shop; // 让我的代理指向水果店A
[my wantToBuySomeFruits]; // 我想去买点水果
运行结果:
说明:水果店的父类中,爆黄的原因是因为,接受了协议代理,却没有完成协议功能,即买水果能力。我们可以空实现,或者将买水果的能力声明为@optional可选即可
结论:我们使用代理模式去买水果时,我们只需要将买水果的业务能力抛出来交给我们的代理,然后找到可以完成该业务的对象水果店,并将代理指向这个水果店即可。水果店和我们的代理完成具体的业务逻辑,我们只需要最后接收结果即可,由上图可以看到,我的代理花了50元最后给我带回了5.10斤的水果
重点:想必从上面的例子中,眼尖的读者已经看出了什么,我们回到最初前言中我抛出的疑问,UITableView如何完成接收我返回的section个数的呢?就如上面我买水果的例子,这里的水果店就是我们通常使用UITableView的Contrlloer,Controller实现了UITableView的delegate中能力,包括section样式,cell样式等等,即水果店实现了我购买水果的业务,而此时我就等于是UITableView,接受代理传回来的样式,数据等等,以做相应的设置
UITableView有delegate和datasource两个代理,这也就说明委托者可以拥有多个代理对象,去完成多种业务
接下来简单说明:
我在买水果的同时,还想再去买点冷饮解解暑,那么我完全可以将买冷饮的能力交给之前的代理,但是有时候为了代理的功能有所区分,我可以再新建声明一个买冷饮的代理对象
MyDataSource
@protocol MyDataSource
@optional
// 我们将买冷饮的能力交给我的MyDataSource
-(CGFloat)buySomeColdDrink;
@end
我的对象将MyDataSource声明为我的属性
#import
#import "MyDelegate.h"
#import "MyDataSource.h"
@interface MyObject : NSObject
@property(weak,nonatomic)id MyDelegate;
// 新增的MyDataSource
@property(weak,nonatomic)id MyDataSource;
// 我想去买水果
-(void)wantToBuySomeFruits;
@end
假如水果店亦兼职买冷饮,我们就可以在水果对像实现买冷饮的业务,水果店对象实现类就变成了如下
@implementation A_FruitShop
// A店表示可以满足我的需求,并实现了买水果的业务
-(CGFloat)buySomeFruitsWithMoney:(NSInteger)money{
self.applePrice = 9.8; // A水果店苹果9块8一斤
CGFloat number = money / self.applePrice ; // 称斤计算
return number; // 算好返回
}
// 水果店A新增卖冷饮的业务
-(CGFloat)buySomeColdDrink{
return 2; // 不要钱,赠了两瓶雪碧
}
@end
将MyDataSource也指向水果店A
MyObject *my = [MyObject new];
A_FruitShop *A_Shop = [A_FruitShop new];
my.MyDelegate = A_Shop; // 让我的代理指向水果店A
my.MyDataSource = A_Shop;
[my wantToBuySomeFruits]; // 我想去买点水果
运行结果
由上图,我们可以看出,我的MyDataSource为我从水果店里带回了2瓶雪碧
这样,我的Delegate和DataSource为我完成了买水果和冷饮的业务,在此过程中,水果店为我提供了相应的服务。
讲到这里,读者应该理解了Delegate的含义了吧?UITableView的Delegate和DataSource是不是不再神秘了呢?
总结:使用代理完成页面传值,仅仅是最基本的使用,类似传递信息功能,我们可以使用代理来为我们分身去完成额外的业务,例如私人定制,根据不同的类型完成不同的功能,而不仅仅拿来传值使用
Delegate的扩展使用
私人定制的另一种使用:未完待续。。。