引言
看到標題的也許有一些老司機看過原文,此文是基於原文翻譯加上自己理解,為了更好的學習iOS~(文章並沒有寫如何運用,主要是探討什麼時候用。)
原文地址:https://www.objc.io/issues/7-foundation/communication-patterns/
我們在開發過程中,常用的兩個物件之間的相互通訊的方式有很五種
- Target-Action
- Delegation
- block
- KVO
- Notifications
本文是討論各個通訊的使用,以及在什麼時候用這些通訊方式。在通訊的過程中,往往一個是接收者,一個是傳送者。
Target-Action
這個方式相信大家見的就很多了,在寫Button或者手勢的時候,都會用到addTagert
這個方法。Target-Action是用於在使用者介面事件響應中傳送訊息的典型模式,一般是用於處理動作訊息。他包含了 兩個資料,一個是選擇子(selector),還有一個是接收人(target)。在iOS中,能觸發Target-Action事件的一般是基於UIControl的(官方文件說是可以任何物件,不過基本上都是繼承與UIControl的)。一般的Target-Action的接收事件如下:
- (void)dosomething:(id)sender;
複製程式碼
在Target-Action中,訊息的接收者其實並不知道傳送者是誰,傳送者也不知道訊息的接送者是誰。所以當target
是nil的時候,會通過響應者鏈找到某一個接收者去響應這個訊息。這個方式的缺點就是傳遞訊息的時候不能帶著自定義的引數。
Delegation
Delegation在蘋果自己的FrameWorks
裡就經常使用,比如我們經常用的 tableViewdelegate
和dataSource
。它允許我們去自定義某一個物件的行為,也可以(被)告訴我們這個物件發生了什麼。在這個通訊過程中,訊息的傳送者需要知道訊息的接收者,也就是這個delegate
。我們在用UITableView
的時候往往會寫tableView.delegate = self
,就是讓tableView
這個訊息的傳送者知道訊息的接收者是誰(self
)。這樣的耦合度會很低,大家應該都深有體會吧,哈哈哈,有時候可能會找不到這個方法在哪兒。。。
delegate protocol
可以定義任何方法,所以你也可以用這些方法傳遞你想要傳遞的引數,而且delegate protocol
可以響應這些方法返回的引數。可見delegate protocol
的通訊方式是非常的靈活和直接。
block
block
也叫閉包函式,講道理的說,只要是Delegation
通訊模式下可以做的事情,都可以用block
代替。相對來說,block
對於程式碼的整體性體驗較好,不會散落在各地。但是blokc
會造成迴圈引用,也可能會提前釋放。總之block
應用起來,總是對新手那麼的不友好。
block
的能夠抓取當前上下文的命名域,怎麼說呢,就是你不需要知道這個具體是什麼東西,裡面是怎麼樣的,你可以直接更具他給的引數或者直接寫你想要寫的程式碼。
#####KVO
KVO
是一種通知物件的屬性發生改變的機制。KVO
是一種靈活的方式去監聽當前物件屬性的改變,尤其是對於系統屬性的監聽,比如說UITableView
的ContentOffSet
這個值改變的監聽,可以幫我們實現一些比較酷炫的UI效果(你懂的)。
KVO
的使用,需要一些必要的條件,比如說你的物件要支援Key-Value Observing機制。而且你要知道這個物件的生命週期,在你不需要的時候移除這個KVO
觀察。
Notifications
Notifications
這通訊方式,就是一種很好的,系統給我們封裝好的,一對多的廣播。他最大的優勢就是可以跨越層級,對程式碼架構的解耦很有幫助。(現在好像不能說一對多是他的優勢了,貌似Swift裡有多Delegate)
iOS
系統在應用過程中會發很多通知,比如說UIKeyboardWillShowNotification
,UITextViewTextDidChangeNotification
等等各種。
Notifications
和KVO
一樣,需要知道接收者的生命週期,在最後生命週期結束的時候登出這個Notifications
。iOS
大部分的生命週期結束的時候都會呼叫- (void)dealloc
。所以其實用起來也比較簡單。(當然你要是發生迴圈引用導致當前物件不能釋放,那就沒辦法了(⊙﹏⊙)b)。
討論
對比了這五種方式,那我們什麼時候用呢。上面文章的作者給了這麼一張圖:
我想分享下自己對於通訊模式的看法。因為不會畫圖,畫在紙上的話,字太醜了,就寫文字吧。。。。
1.是否直接進行物件的互動而且不需要引數,比如說手勢,Button這些的 。如果是的話,就用Target-Action
。
2.是否是多層級的,兩個物件是否有聯絡,如果不是的話,就可以用Notifications
。
3.既然兩個物件是有聯絡的,當你需要監聽值發生變化的時候,可以使用KVO
。(單存值變化,而不是其他動作響應的情況下)
4.我是否需要知道這個物件的具體東西,上下文的具體命名域。如果不需要的話,這個時候使用Block
會好一點。比如說我們網路請求時候的回撥各種,只要輸入請求引數,然後寫好回撥。中間發生了什麼,其實你知道不知道,並不影響使用。
5.對於Delegation
和block
我覺得是大部分情況下是可以互相替換的,因為關於迴圈引用這方面,現在各種WeakSelf
,StrongSelf
的文章。不過在某些情況,比如說你的訊息傳送者需要用到接收者給的返回值的時候,這個時候用Delegation
在設計上來說比Block
更好。
End
其實對於通訊模式這種理解,對於整體架構,包括響應式程式設計都有很好的幫助。