关于代理模式的使用,我们都很熟悉。代理的使用场景是为了解决一对一的消息传递。比如A想执行方法M 但是A不方便执行。这时我们可以将B设置为A的代理 让B去执行。代理模式在日常开发中被大量使用,这里不再去赘述。今天我想说说的是self.delegate = self ,即自身代理的问题。
什么叫自身代理?
我给大家举个最简单的例子:
当我们自定义了一个UITableView。我们可以将其的代理和数据源设置为自己。
#import "TestTableView.h"
@interface TestTableView ()<UITableViewDelegate>
@end
@implementation TestTableView
-(instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
self.delegate = self;
}
return self;
}
#pragma mark UITableViewDelegate
(这里实现代理方法)........
@end
这样是不是比较好理解?但其实自身代理有更为复杂的应用场景。我结合一下自己项目里的业务需求讲述一下。
我们简化一下需求:比如一个企业管理软件。有个需求是展示企业组织架构。有一个控制器A。A里面是部门列表(销售部,市场部,人事部,技术部等等)。每个部门点击去是当前部门的子部门列表(比如技术部点进去 可以有运维组 前端组 后端组等等),子部门列表中的每个部门点进去也是当前子部门的子部门列表(比如前端组点进去 可以有web段 移动端等等),以此类推 一直循环下去。
拿到这个需求我们怎么构思代码?
显而易见,不可能每个层级的部门列表都写一个页面或者控制器去展示。假如有家大公司部门层级很深,你总不可能一个个页面去对应的写一套代码吧。所以不管它是几级部门,我们都可以用一个类去描述(这里假设是Class A)。我们用A初始化一个对象,比如一级部门A0,从A0中任意点击一个部门,进入其子部门(即二级部门),我们需要再创建一个A的对象A00, 然后从A0跳转到A00。此时A0和A00的内存虽然不同,但其储存的代码是一模一样的。从二级部门进入三级部门同样的道理。
这个需求的数据展示很简单。那么我们再来加一个简单的需求,如果希望在每一级部门的页面都可以进行其父部门的操作呢?比如在A0的子部门列表中有个按钮可以删除A0部门。看到这里你们可能有点晕 这里我用钉钉的组织架构功能举个例子。
从公司主页点进去是一级部门列表

从市场销售部点进去,是二级部门列表

点击右上角的更多我们可以操作市场销售部的属性,比如删除市场销售部,或者重命名市场销售部。
那这个需求又如何去构思代码?
这时候我们就需要消息传递了。
我的做法是在A0跳转到A00的时候将A00的代理设置为A0,因为A00和A0都是用A去描述的,所以我们可以用 self.delegate = self。
这是我项目中的代码(因为实际业务需求比我举的例子要复杂的多,所以这里代码比较繁琐)申明一个类 OrganizationalStructureController
用来描述每一级部门列表,在 OrganizationalStructureController
中做层级跳转的时候再创建一个 OrganizationalStructureController
的对象,把需要的数据传递过去,并设置其代理为本身。这里的vc好比是A00,self是A0。 vc.delegate=self
即设置A00的代理为A0。

这是OrganizationalStructureController的代理方法

当我们从A00界面点击删除的时候,A00的代码会执行 makeSureDeleteDepartment
的方法,而A00的代理是A0(我们在A0 跳转到 A00的方法中已经设置了)。所以当删除方法执行的时候,A0会执行 deleteIndexpath:
的方法(这里有点绕 注意不是A00执行 虽然该代码同样存在于A00上 但是走的却是A0的代码)。 deleteIndexpath:
方法里的self其实是A0,也就是走的是A0的数据源更新。

看到这里,可能有的人会想为什么要这么麻烦,直接在 OrganizationalStructureController
的 viewWillApper
的方法里去请求最新的数据进行渲染不就行了。但实际上需求不仅仅是删除这么简单的操作,这里只是举个例子,引入自身代理的这种思想。
网友评论