Delegate通俗理解,使用详解,你还在仅仅拿来传值使吗?

前言

最初接触到Delegate,是页面之间的传递数据,也就是网上出现的大部分页面传值教程,即:A页面跳转B页面,B跳回A时需要传递一些数据,这时我理解的Delegate仅限于页面传值;后来常常封装一些东西时,也常用Delegate来传递消息和值,这时理解的Delegate是NSObject之间的消息传递者,但是却越来越看不懂Delegate了,联想到UITableView的Delegate和Datasource,一直有疑问,系统是如何得到并使用我们设置的section个数,cell样式来显示Table样式的呢,它扮演了什么角色?


代理,本意是代替某对象去完成某种业务,如果仅仅是去完成消息提醒或者传递数据是不是大材小用了!!??正好有点时间,我好好的研究了一下,发现了Delegate的更多的作用,这里跟大家分享一下,希望能够帮助新人更好的理解和掌握Delegate的使用。


一、没有代理的情况

首先我们在没有代理的情况下,我们如何完成一些业务呢?

下面我用一些生活的例子,通俗的讲解一下Delegate的使用;

业务一:我想去买一些水果

突然有一天,我心血来潮的想吃点水果,便找到附近的水果店去买些水果。

这里有两个对象,我和水果店,钱和水果是两者的业务关系

首先定义一下我和水果店对象:

Delegate通俗理解,使用详解,你还在仅仅拿来传值使吗?_第1张图片
我和水果店

接着我们来定义水果店售卖水果店业务

.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中的接口,只有方法声明,没有实现

Delegate通俗理解,使用详解,你还在仅仅拿来传值使吗?_第2张图片
新建代理协议

我们将购买水果的能力分离出来赋予代理

#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的扩展使用

私人定制的另一种使用:未完待续。。。

你可能感兴趣的:(Delegate通俗理解,使用详解,你还在仅仅拿来传值使吗?)