delegate是iOS中一种常见的设计模式,是一种消息传递的的方式,常见的消息传递方式还有如下几种:json
通知:在iOS中由通知中心进行消息接收和消息广播,是一种一对多的消息传递方式。
代理:是一种通用的设计模式,iOS中对代理支持的很好,由代理对象、委托者、协议三部分组成。
block:iOS4.0中引入的一种回调方法,能够将回调处理代码直接写在block代码块中,看起来逻辑清晰代码整齐。
target action:经过将对象传递到另外一个类中,在另外一个类中将该对象当作target的方式,来调用该对象方法,从内存角度来讲和代理相似。
KVO:NSObject的Category-NSKeyValueObserving,经过属性监听的方式来监测某个值的变化,当值发生变化时调用KVO的回调方法。
咱们能够经过一个简单的例子来解释什么是代理?什么是协议?设计模式
有个baby不会本身吃饭和洗澡等等作一些事情,因而baby就请了一个保姆,因而baby和保姆之间有了一个协议(Protocol)合同,协议合同中写明了保姆须要作什么事情, 而保姆就是要去完成这个协议中规定要作的事的代理人。
即:baby和保姆之间有个协议,保姆遵照该协议,因而保姆就须要实现该协议中的条款成为baby代理(delegate)人,而baby就是保姆的委托方。ui
说白了,代理的做用你们能够简单粗暴的理解为:"本身作不了的事情,就去雇佣一个能够作这些事的人,交给他去作!"atom
因此,咱们从上面这个关系中能够看出,代理设计到了三个东西:委托方、代理方、协议,三者关系以下图所示↓↓↓spa
协议:用来指定代理双方能够作什么,必须作什么。
代理:根据指定的协议,完成委托方须要实现的功能。
委托:根据指定的协议,指定代理去完成什么功能。
在实际应用中经过协议来规定代理双方的行为,协议中的内容通常都是方法列表,当代理方成为委托方代理并遵照相关协议后,委托方可让代理方执行协议中规定的操做。设计
协议有两个修饰符@optional和@required,建立一个协议若是没有声明,默认是@required状态(必须实现)的。这两个修饰符只是约定代理是否强制须要遵照协议,若是@required状态的方法代理没有遵照,会报一个黄色的警告,只是起一个约束的做用,没有其余功能。【@required是须要咱们必须实现的(不实现也只是报个黄色警告而已)。@optional是能够选择实现的.】3d
不管是@optional仍是@required,在委托方调用代理方法时都须要作一个判断,判断代理是否实现当前方法,不然会致使崩溃。代理
示例:// 判断代理对象是否实现这个方法,没有实现会致使崩溃 if([self.delegate respondsToSelector:@selector(userLoginWithUsername:password:)]) { [self.delegate userLoginWithUsername:self.username.text password:self.password.text]; }
项目中有两个控制器,CDMyAddressListController(如下简称List)是用户地址列表控制器,CDAddAddressController(如下简称add)用户添加/删除地址的控制器,CDAddAddressController是从CDMyAddressListController push出来的指针
如今的需求是,当用户在CDAddAddressController删除地址后,要CDMyAddressListController中展示的是最新的数据:code
这里能够用到的方法不少,好比说在删除地址成功后发送通知,CDMyAddressListController接收到通知后作刷新处理,或者最笨的方法就是每次进入地址列表页都进行刷新,固然,咱们也能够经过代理来实现:
首先,分析谁是委托方,谁是代理方:
委托方经过协议来让代理方作事情的,而在这个项目中,add控制器想要在特定时候让List控制器去刷新,因此add控制器就是委托方,而List控制器就是代理方。
接下来,咱们来看协议:
由于这个协议只是在add这个类中会用到,因此写在add类内部就能够,不用再建立pertocol文件存放了;
这个协议只规定了一件事情,那就是刷新数据,并且当委托方发出需求是,代理方必需要实现,因此是@required状态
// // CDAddAddressController.h // xx // // Created by xx on 2019/4/11. // Copyright © 2019 xx. All rights reserved. // #import <UIKit/UIKit.h> @class CDMyAddressListModel; //制定协议 @protocol CDAddAddressControllerDelegate <NSObject> - (void)reloadDataToRefresh; @end @interface CDAddAddressController : UIViewController
//使用协议修饰属性,声明当前属性时已经遵照协议的,当代理方出现了该协议中的方法时,编译器就不会报错
//delegate属性就是创建委托方和代理方的连接,→→ @property(nonatomic,weak) id delegate;
@property(nonatomic,weak) id<CDAddAddressControllerDelegate> delegate;
@property(nonatomic,strong) CDMyAddressListModel *model; @end
制定完协议后,当委托方须要的时候就能够指定代理方作事了:
CDAddAddressController.m //删除地址 - (void)delete{ // 初始化对话框 UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"是否确认删除改地址?" preferredStyle:UIAlertControllerStyleAlert]; // 肯定注销 UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"肯定" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) { [[CDWebService instance]deleteMyAddressWithParameters:@{@"address_id":self.model.address_id} success:^(id json) { if ([json[@"code"]integerValue] == 100) { [CDCommentAlertView showRequestStatus:statusNormal explain:@"删除成功"]; //要求代理方执行协议中的方法 // 判断代理方法是否存在 if ([self.delegate respondsToSelector:@selector(reloadDataToRefresh)]) { [self.delegate reloadDataToRefresh]; } [self .navigationController popViewControllerAnimated:YES]; }else{ [CDCommentAlertView showRequestStatus:statusNormal explain:json[@"message"]]; } } failure:^(NSError *error) { [CDUtils alertError:error]; }]; }]; UIAlertAction *cancelAction =[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]; [alert addAction:okAction]; [alert addAction:cancelAction]; [self presentViewController:alert animated:true completion:nil]; }
而代理方如今须要作的就是成为代理、遵照协议、实现代理方法
CDMyAddressListController.m //在声明部分遵照协议< CDAddAddressControllerDelegate > //添加/删除地址 - (void)addAddress{ CDAddAddressController *add = [[CDAddAddressController alloc]init]; add.delegate = self; [self.navigationController pushViewController:add animated: YES]; } #warning CDAddAddressControllerDelegate //经过代理来 - (void)reloadDataToRefresh{ [self loadNewData]; }
至此,一个完整的代理就完成了。
其实代理的实现没有涉及到什么底层的东西,只不过是代理对象内存的传递和操做。
咱们在委托类设置代理对象后,实际上只是用一个id类型的指针将代理对象进行了一个弱引用。委托方让代理方执行操做,其实是在委托类中向这个id类型指针指向的对象发送消息,而这个id类型指针指向的对象,就是代理对象。
按上面例子来讲的话,就是
CDAddAddressController *add = [[CDAddAddressController alloc]init]; //self就是list对象,self设置成add控制器的代理,实际上也就是成为add控制器的一个属性而已 add.delegate = self; [self.navigationController pushViewController:add animated: YES];
//要求代理方执行协议中的方法 // 判断代理方法是否存在 //delegate这个属性自己存放的就是list控制器这个对象,检测代理方法是否存在也就是至关与查看list对象中是否存在这个方法 if ([self.delegate respondsToSelector:@selector(reloadDataToRefresh)]) { //至关于 [list reloadDataToRefresh]; 也就是list对象调用本身的方法 [self.delegate reloadDataToRefresh]; }
首先咱们要知道咱们在建立对象的时候若是没有特别说明的话咱们默认的是strong强引用(在OC中,对象默认都是强指针),因此咱们在list控制器中建立add对象后,list对象使其对add对象有一个强引用,
而add中的delegate其实就是引用的list对象,若是用strong来修饰的话,那么这两个引用都是强引用,就会出现循环引用的问题,致使双方都没办法去释放:
因此咱们须要用weak来修饰delegate属性,这样add属性对list是一个弱引用,list对add是强引用,这样就避免了循环引用