iOS代理Delegate理解

本文来源:www.greatytc.com/p/67293140c570

相信提起代理(delegate),无论你是否刚步入iOS的编程世界,应该一定都会听说过它,我们经常会使用到代理(delegate)的设计模式,这是iOS中一种常用的消息传递的方式,也可以通过这种方式来传递一些参数。这篇文章会涵盖代理的使用技巧和原理,以及代理的内存管理等方面的知识。

≈那么究竟什么是代理模式呢?
举个在我们iOS行业中经典形象的例子来,以便大家能够更好的理解代理模式的含义:

有个婴儿(是男是女就不要去纠结了~~~),baby不会自己吃饭和洗澡等等做一些事情,于是baby的Mommy就请了一个保姆,于是baby和保姆之间商定了一个协议合同,协议合同中写明了保姆需要做什么事情, 而保姆就是要去完成这个协议中规定要做的事的代理人
即:baby和保姆之间有个协议,保姆遵守该协议,于是保姆就需要实现该协议中的条款成为baby代理人。

说白了,代理的作用大家可以简单粗暴的理解为:"自己做不了的事情,就去雇佣一个可以做这些事的人,交给他去做!"

iOS中消息传递方式

在iOS中有很多种消息传递方式,首先简单了解一下常见的消息传递的几种方式。

1.通知(notification)

在iOS中由通知中心进行消息接收和消息广播,是一种一对多的消息传递方式。(使用后需要移除通知)

2.代理(delegate):

是一种通用的设计模式,iOS中对代理支持的很好,由代理对象、委托者、协议三部分组成。

3.block

在iOS 4.0中开始引入的一种回调方法,可以将回调处理代码直接写在block代码块中,看起来逻辑清晰代码整齐。

4.target action

通过将对象传递到另一个类中,在另一个类中将该对象当做target的方式,来调用该对象方法,从内存角度来说和代理类似。

5.KVO

NSObject的Category(分类)-NSKeyValueObserving,通过对属性进行监听的方式来监测某个值的变化,当值发生变化时调用KVO的回调方法。

代理的基本使用

代理是一种通用的设计模式,在iOS中有特定的语法来实现代理模式,OC语言可以通过@Protocol实现协议。

代理主要由三部分组成:

协议:用来指定代理双方可以做什么,必须做什么。
代理:根据协议,完成委托方需要实现的功能(方法)。
委托:根据协议,指定代理去完成什么功能。

协议(Protocol)的概念

2509206-1630b14d29341db3.png

从上图中我们可以看到三方之间的关系,在实际应用中通过协议来规定代理双方的行为,协议中的内容通常情况都是方法列表,当然也可以定义属性.(后面会介绍协议属性)协议是公共的,如果只是单单某个类去使用,我们常做的就是写在某个类中。如果多个类都是使用同一个协议,这里建议大家创建一个Protocol文件,在这个文件中制定协议。遵循的协议可以被继承,!

例如:UITableView,继承自UIScrollView,所以也将UIScrollViewDelegate继承了过来,这样我们就可以通过代理方法获取UITableView偏移量等状态参数。
协议只能定义公用的一套接口,类似于一个约束代理双方的作用。但不能提供具体的实现方法,实现方法需要代理对象(可以理解为接受协议遵守协议的代理人)去实现。
协议可以继承其他协议,也可以继承多个协议,在iOS中对象是不支持多继承的,而协议是可以多继承。
协议有两个修饰符@optional和@required,创建一个协议如果没有声明修饰符,默认是@required状态的。这两个修饰符只是约定代理是否强制需要遵守协议,如果@required状态的方法代理没有遵守,Xcode会报一个黄色的警告,@required是需要我们必须实现的。@optional是可以选择实现的.

下面我们将用一个小例子来讲解一下这个问题

我想给我的爱车清理一下,不过上海的天气太热了,不想自己动手.于是去洗车店,委托洗车行帮我把车子清理干净(指定协议).然后洗车店的人会帮助我将我的车子洗干净.!

在这个过程当中,洗车行就是我的代理.而我就是委托方,我要求洗车行将我的车子清理干净,这就相当于制定了协议.至于洗车的过程是洗车阿航去处理,不需要我来操作,我只要付钱给车行,等待车行将我的车洗赶紧就好.这个过程中我付的钱就相当于是传递的参数,最后洗干净的车子就是处理的结果.
在等待车行洗车的过程中,突然间我觉得肚子饿了,于是打给了某家餐馆进行委托订餐,那么我就是委托方,而上面的洗车行无法提供给我,我要的东西.所以这个餐馆成为了我的又一个代理.也就是说一个委托方可以有多个代理对象在iOS中一个代理可以有多个委托方,而一个委托方也可以有多个代理。
我指定了洗车行和餐馆两个代理,也可以再指定其他等多个代理,委托方也可以为多个代理服务。代理对象在很多情况下其实是可以复用的,可以创建多个代理对象为多个委托方服务,

代理使用原理

代理实现流程

在iOS中代理的本质就是代理对象内存的传递和操作,我们在委托类设置代理对象后,实际上只是用一个id类型的指针将代理对象进行了一个弱引用。委托方让代理方执行操作,实际上是在委托类中向这个id类型指针指向的对象发送消息,而这个id类型指针指向的对象,就是代理对象。

代理原理

我们发现,其实委托方的代理属性本质上就是代理对象自身,设置委托代理就是代理属性指针指向代理对象,相当于代理对象只是在委托方中调用自己的方法,如果方法没有实现就会导致崩溃。从崩溃的信息上来看,就可以看出来是代理方没有实现协议中的方法导致的崩溃。
而协议只是一种语法,是声明委托方中的代理属性可以调用协议中声明的方法,而协议中方法的实现还是有代理方完成,而协议方和委托方都不知道代理方有没有完成,也不需要知道怎么完成。

代理内存管理

为什么我们在设置代理属性要使用weak呢?
我们定义的指针默认都是__strong类型的,而属性本质上也是一个成员变量和set、get方法构成的,strong类型的指针会造成强引用,会造成####循环引用。
由于代理对象使用强引用指针,引用创建的委托方LoginVC对象,并且成为LoginVC的代理。这就会导致LoginVC的delegate属性强引用代理对象,导致循环引用的问题,最终两个对象都无法正常释放。
简单理解就是:A引用B,B引用A.
弱引用

我们将LoginVC对象的delegate属性,设置为弱引用属性。这样在代理对象生命周期存在时,可以正常为我们工作,如果代理对象被释放,委托方和代理对象都不会因为内存释放导致的Crash。
但是,这样还有点问题,真的不会崩溃吗?
下面两种方式都是弱引用代理对象,但是第一种在代理对象被释放后不会导致崩溃,而第二种会导致崩溃。

@property (nonatomic, weak) id delegate;
@property (nonatomic, assign) id delegate;

weak和assign是一种“非拥有关系”的指针,通过这两种修饰符修饰的指针变量,都不会改变被引用对象的引用计数。但是在一个对象被释放后,weak会自动将指针指向nil,而assign则不会。在iOS中,向nil发送消息时不会导致崩溃的,所以assign就会导致野指针的错误unrecognized selector sent to instance。
所以我们如果修饰代理属性,还是用weak修饰吧,比较安全。

为什么要使用代理对象?

随着项目越来越复杂,控制器也随着业务的增加而变得越来越臃肿。对于这种情况,很多人都想到了最近比较火的MVVM设计模式。但是这种模式学习曲线很大不好掌握,对于新项目来说可以使用,对于一个已经很复杂的大中型项目,就不太好动框架这层的东西了。
在项目中用到比较多的控件应该就有UITableView了,有的页面往往UITableView的处理逻辑很多,这就是导致控制器臃肿的一个很大的原因。对于这种问题,我们可以考虑给控制器瘦身,通过代理对象的方式给控制器瘦身。

代理对象

可以看出,我们将UITableView的delegate和DataSource单独拿出来,由一个代理对象类进行控制,只将必须控制器处理的逻辑传递给控制器处理。
UITableView的数据处理、展示逻辑和简单的逻辑交互都由代理对象去处理,和控制器相关的逻辑处理传递出来,交由控制器来处理,这样控制器的工作少了很多,而且耦合度也大大降低了。这样一来,我们只需要将需要处理的工作交由代理对象处理,并传入一些参数即可。

代理和block的选择

在iOS中的回调方法有很多,而代理和block功能更加相似,都是直接进行回调,那我们应该用哪个呢,或者说哪个更好呢?
其实这两种消息传递的方式,没有哪个更好、哪个不好代理更加面相过程,block则更面向结果。从设计模式的角度来说,代理更佳面向过程,而block更佳面向结果。
单从性能上来说,block的性能消耗要大于delegate,因为block会涉及到栈区向堆区拷贝等操作,。而代理只是定义了一个方法列表,在遵守协议对象的objc_protocol_list中添加一个节点,在运行时向遵守协议的对象发送消息即可。如何选择要看情景,和你自己的习惯了.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容