iOS开发---图解代理

iOS开发—图解代理

什么是代理?

代理(Delegate)是iOS开发中的一种重要的消息传递方式,是iOS开发中普遍使用的通用设计模式,iOS集成开发环境Xcode中,提供大量的控件,例如UITableViewUIScrollViewDelegateUISearchView等都是用代理机制实现消息传递。

  • 官方解释是不是看起来一脸懵逼,下面我们从生活中举个?

有一个婴儿,他本身不会自己吃饭和洗澡等等一些事情,于是婴儿就花钱请了一个保姆,于是婴儿和保姆之间商定了一个协议,协议中写明了保姆需要做什么事情, 而保姆就是这个代理人。

即:婴儿和保姆之间有个协议,保姆继承该协议,于是保姆就需要实现该协议中的条款成为代理人。你的父母雇佣了这个保姆,父母就是委托人。父母雇佣保姆需要支付薪酬,这就是传递的参数,保姆给婴儿洗了澡这就是处理结果

代理的组成

  • 代理机制由代理对象、委托者、协议三部分组成
  • 下面我们用一张图来展示之间的关系

协议

用来指定代理双方可以做什么,必须做什么。

协议的作用和内容
  • 从上图我们可以看到三方之间的关系,在实际应用中通过协议来规定代理双方的行为,协议中的内容一般都是方法列表,当然也可以定义属性
协议定义地点
  • 协议是公共的定义,如果只是某个类使用,我们常做的就是写在某个类中。如果是多个类都是用同一个协议,建议创建一个Protocol文件,在这个文件中定义协议。
协议的继承
  • 遵循的协议可以被继承,例如我们常用的UITableView,由于继承自UIScrollView的缘故,所以也将UIScrollViewDelegate继承了过来,我们可以通过代理方法获取UITableView偏移量等状态参数。

  • 协议只能定义公用的一套接口,类似于一个约束代理双方的作用。但不能提供具体的实现方法,实现方法需要代理对象去实现。协议可以继承其他协议,并且可以继承多个协议,在iOS中对象是不支持多继承的,而协议可以多继承。

协议的修饰符

创建一个协议如果没有声明,默认是@required状态的,@required状态的方法代理没有遵守,会报一个黄色的警告,只是起一个约束的作用,没有其他功能

  • @optional:下的方法可选择实现

  • @required:下的方法必须实现

如何定义协议
#import <Foundation/Foundation.h>
@protocol Login <NSObject>
@optional
- (void)userLoginWithUsername:(NSString *)username password:(NSString *)password;
@end

代理对象

根据指定的协议,完成委托方需要实现的功能。

如何实现代理对象
// 遵守登录协议
//.h文件中
@interface ViewController () <Protocol> 
@end

//.m文件中
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
  
    LoginViewController *loginViewController = [[LoginViewController alloc] init];
    loginViewController.delegate = self;
    [self.navigationController pushViewController:loginViewController animated:YES];
}

/**
 *  代理方实现具体登录细节
 */
- (void)userLoginWithUsername:(NSString *)username password:(NSString *)password {
    NSLog(@"username : %@, password : %@", username, password);
}

委托者

根据指定的协议,指定代理去完成什么功能。

如何定义委托者

定义委托类,这里简单实现了一个用户登录功能,将用户登录后的账号密码传递出去,由代理来处理具体登录细节。

#import <UIKit/UIKit.h>
#import "Protocol.h"
/**
 *  当前类是委托类。用户登录后,让代理对象去实现登录的具体细节,委托者不需要知道其中实现的具体细节。
 */
//.h文件中
@interface LoginViewController : UIViewController
// 通过属性来设置代理对象
@property (nonatomic, weak) id <Protocol> delegate;
@end

//.m文件中
@implementation LoginViewController
- (void)loginButtonClick:(UIButton *)button {
  // 判断代理对象是否实现这个方法,没有实现会导致崩溃
  if ([self.delegate respondsToSelector:@selector(userLoginWithUsername:password:)]) {
      //调用代理对象的登录方法,代理对象去实现登录方法
      [self.delegate userLoginWithUsername:self.username.text password:self.password.text];
  }
}
代理对象和委托者对应关系
  • 下面我还是举个?来说明代理对象和委托者的关系

    1. 由于我的?脏了,不想自己动手清洗他,于是委托洗车店帮我把车子洗干净(协议内容),然后洗车店就会帮我把车洗干净。在这个过程中,我是委托者,洗车店是代理对象,洗车是协议,我给洗车店薪酬是参数,洗车店帮我把车洗好是结果
    2. 在洗车的过程中,突然我有点口渴,但是洗车店不提供饮品服务,所以我只能通过APP在别的商家订了一杯柠檬水。在这个过程中,我是委托者,饮品店是代理对象,买饮品是协议,我支付饮品店薪酬是参数,饮品店把饮品送过来是结果.
    3. 在我等待洗车的过程中,该洗车店又接待了别的车;我在洗车的同时,还喝了饮品。
  • 我在洗车同时,又点了饮品,说明一个委托方可以有多个代理对象

  • 洗车行在给我写的同时,又接待了别的客户,说明一个代理对象可以有多个委托方

  • 下面我们用一张图来展示之间的关系

代理实现原理

实现流程
  • 我们先看一张图大致了解他们之间的流程关系

  • iOS中代理的本质就是**对代理对象内存的传递和操作,*
  • 委托方和代理方如何通讯
    • 我们在委托类设置代理对象后,实际上只是用一个id类型的指针指向代理对象,并将代理对象进行了一个弱引用。
  • 委托方的调用方法,代理方如何实现
    • 委托方让代理方执行某个方法,实际上是在委托类中向这个id类型指针指向的对象发送消息,而这个id类型指针指向的对象,就是代理对象。
  • 什么是协议?
    • 协议其实就是一种语法,委托方中的代理属性可以调用、协议中声明的方法而协议中方法的实现还是有代理方完成
内存管理
为什么我们设置代理属性都使用weak呢?
  • 我们定义的指针默认都是__strong类型的,而属性本质上也是一个成员变量和setget方法构成的,strong类型的指针会造成强引用,必定会影响一个对象的生命周期,这也就会形成循环引用。

  • 上图中,由于代理对象使用强引用指针,指向创建的委托方loginViewController对象,并且委托方delegate属性强引用代理对象。这就会导致LoginVCdelegate属性强引用代理对象,导致循环引用的问题,最终两个对象都无法正常释放。

  • 我们将loginViewController对象的delegate属性,设置为弱引用属性。这样在代理对象生命周期存在时,可以正常为我们工作,如果代理对象被释放,委托方和代理对象都不会因为内存释放导致的Crash
弱引用有weak和assign两种方式,用哪一种好?
@property (nonatomic, weak) id <Protocol> delegate;
@property (nonatomic, assign) id <Protocol> delegate;
  • 下面两种方式都是弱引用代理对象,但是第一种在代理对象被释放后不会导致崩溃,而第二种会导致崩溃。
  • weakassign是一种“非拥有关系”的指针,通过这两种修饰符修饰的指针变量,都不会改变被引用对象的引用计数。但是在一个对象被释放后,weak会自动将指针指向nil,而assign则不会。在iOS中,向nil发送消息时不会导致崩溃的,所以assign就会导致野指针的错误unrecognized selector sent to instance

代理给ViewController瘦身

  • 在我们写项目时,特别是主界面会随着处理的逻辑越来越多它会越来越肥。对于新项目来说MVVM设计模式是一种最好的选择,但是对于一个已经很复杂的项目来说,代理是很很好的方式。

  • 这是我们平成控制器的使用

  • 这是优化后的控制器

  • 从上面两张图可以看出,我们将UITableViewdelegateDataSource单独拿出来,由代理对象进行控制,只将必须控制器处理的逻辑传递给控制器处理。UITableView的数据处理、展示逻辑和简单的逻辑交互都由代理对象去处理,和控制器相关的逻辑处理传递出来,交由控制器来处理,这样控制器的工作少了很多,而且耦合度也大大降低了。这样一来,我们只需要将需要处理的工作交由代理对象处理,并传入一些参数即可。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值