看到标题的也许有一些老司机看过原文,此文是基于原文翻译加上自己理解,为了更好的学习 iOS~(文章并没有写如何运用,主要是探讨什么时候用。) 原文地址:https://www.objc.io/issues/7-foundation/communication-patterns/
我们在开发过程中,常用的两个对象之间的相互通信的方式有很五种
这个方式相信大家见的就很多了,在写 Button 或者手势的时候,都会用到 addTagert 这个方法。Target-Action 是用于在用户界面事件响应中发送消息的典型模式,一般是用于处理动作消息。他包含了 两个数据,一个是选择子(selector),还有一个是接收人(target)。在 iOS 中,能触发 Target-Action 事件的一般是基于 UIControl 的(官方文档说是可以任何对象,不过基本上都是继承与 UIControl 的)。一般的 Target-Action 的接收事件如下:
- - (void) dosomething: (id) sender;
在 Target-Action 中,消息的接收者其实并不知道发送者是谁,发送者也不知道消息的接送者是谁。所以当 target 是 nil 的时候,会通过响应者链找到某一个接收者去响应这个消息。这个方式的缺点就是传递消息的时候不能带着自定义的参数。
Delegation 在苹果自己的 FrameWorks 里就经常使用,比如我们经常用的 tableViewdelegate 和 dataSource。它允许我们去自定义某一个对象的行为,也可以 (被) 告诉我们这个对象发生了什么。在这个通信过程中,消息的发送者需要知道消息的接收者,也就是这个 delegate。我们在用 UITableView 的时候往往会写
,就是让 tableView 这个消息的发送者知道消息的接收者是谁 (self)。这样的耦合度会很低,大家应该都深有体会吧,哈哈哈,有时候可能会找不到这个方法在哪儿。。。 delegate protocol 可以定义任何方法,所以你也可以用这些方法传递你想要传递的参数,而且 delegate protocol 可以响应这些方法返回的参数。可见 delegate protocol 的通信方式是非常的灵活和直接。
- tableView.delegate = self
block 也叫闭包函数,讲道理的说,只要是 Delegation 通讯模式下可以做的事情,都可以用 block 代替。相对来说,block 对于代码的整体性体验较好,不会散落在各地。但是 blokc 会造成循环引用,也可能会提前释放。总之 block 应用起来,总是对新手那么的不友好。 block 的能够抓取当前上下文的命名域,怎么说呢,就是你不需要知道这个具体是什么东西,里面是怎么样的,你可以直接更具他给的参数或者直接写你想要写的代码。
#####KVO KVO 是一种通知对象的属性发生改变的机制。KVO 是一种灵活的方式去监听当前对象属性的改变,尤其是对于系统属性的监听,比如说 UITableView 的 ContentOffSet 这个值改变的监听,可以帮我们实现一些比较酷炫的 UI 效果(你懂的)。 KVO 的使用,需要一些必要的条件,比如说你的对象要支持 Key-Value Observing 机制。而且你要知道这个对象的生命周期,在你不需要的时候移除这个 KVO 观察。
Notifications 这通讯方式,就是一种很好的,系统给我们封装好的,一对多的广播。他最大的优势就是可以跨越层级,对代码架构的解耦很有帮助。(现在好像不能说一对多是他的优势了,貌似 Swift 里有多 Delegate) iOS 系统在应用过程中会发很多通知,比如说
,
- UIKeyboardWillShowNotification
等等各种。 Notifications 和 KVO 一样,需要知道接收者的生命周期,在最后生命周期结束的时候注销这个 Notifications。iOS 大部分的生命周期结束的时候都会调用 - (void)dealloc。所以其实用起来也比较简单。(当然你要是发生循环引用导致当前对象不能释放,那就没办法了 (⊙﹏⊙)b)。
- UITextViewTextDidChangeNotification
对比了这五种方式,那我们什么时候用呢。上面文章的作者给了这么一张图:
我想分享下自己对于通讯模式的看法。因为不会画图,画在纸上的话,字太丑了,就写文字吧。。。。 1. 是否直接进行对象的交互而且不需要参数,比如说手势,Button 这些的 。如果是的话,就用 Target-Action。 2. 是否是多层级的,两个对象是否有联系,如果不是的话,就可以用 Notifications。 3. 既然两个对象是有联系的,当你需要监听值发生变化的时候,可以使用 KVO。(单存值变化,而不是其他动作响应的情况下) 4. 我是否需要知道这个对象的具体东西,上下文的具体命名域。如果不需要的话,这个时候使用 Block 会好一点。比如说我们网络请求时候的回调各种,只要输入请求参数,然后写好回调。中间发生了什么,其实你知道不知道,并不影响使用。 5. 对于 Delegation 和 block 我觉得是大部分情况下是可以互相替换的,因为关于循环引用这方面,现在各种 WeakSelf,StrongSelf 的文章。不过在某些情况,比如说你的消息发送者需要用到接收者给的返回值的时候,这个时候用 Delegation 在设计上来说比 Block 更好。
其实对于通讯模式这种理解,对于整体架构,包括响应式编程都有很好的帮助。
来源: https://juejin.im/post/5a43448b51882527a00fa3cb