詳解iOS中跨頁(yè)面狀態(tài)同步方案比較
由于團(tuán)隊(duì)希望項(xiàng)目能夠去 CoreData 化,而以往狀態(tài)同步都是依賴于 CoreData 的NSFetchedResultsController
。因此去 CoreData 則必須尋找一種替代方案來(lái)進(jìn)行狀態(tài)同步。
NotificationCenter
狀態(tài)同步實(shí)際是一對(duì)多的場(chǎng)景,也就是一個(gè)事件可以被多個(gè)觀察者監(jiān)聽(tīng)到。而蘋(píng)果的系統(tǒng)框架自帶的 NotificationCenter 正是用來(lái)適配這種場(chǎng)景,并且其也是被系統(tǒng)框架本身及我們開(kāi)發(fā)者大面積使用的。用法如下:
- 定義通知名字,以及需要額外傳遞信息的 key
- 基于 target-action 的方式注冊(cè)通知
open func addObserver(_ observer: Any, selector aSelector: Selector, name aName: NSNotification.Name?, object anObject: Any?)
實(shí)現(xiàn)監(jiān)聽(tīng)通知的方法
func onReceivedNotification(note: NSNotification)
發(fā)送通知,可以傳遞發(fā)送通知的對(duì)象(object)以及一些額外的信息(userInfo)
open func post(name aName: NSNotification.Name, object anObject: Any?, userInfo aUserInfo: [AnyHashable : Any]? = nil)
移除注冊(cè)的通知
open func removeObserver(_ observer: Any, name aName: NSNotification.Name?, object anObject: Any?)
當(dāng)然 NotificationCenter 也提供了一種更加便利基于 block 的方式注冊(cè)監(jiān)聽(tīng)通知,其將 2,3 兩個(gè)步驟整合為 1 個(gè)步驟。
open func addObserver(forName name: NSNotification.Name?, object obj: Any?, queue: OperationQueue?, using block: @escaping (Notification) -> Void) -> NSObjectProtocol
整體流程很清晰,簡(jiǎn)單易用,但是卻有一個(gè)嚴(yán)重的缺點(diǎn) —— 弱類型。我們接收到的是一個(gè)NSNotification
對(duì)象。
open class NSNotification : NSObject, NSCopying, NSCoding { open var name: NSNotification.Name { get } open var object: Any? { get } open var userInfo: [AnyHashable : Any]? { get } }
假設(shè)我們需要傳遞一個(gè)關(guān)注狀態(tài)改變的信息,那么需要包含關(guān)注更改后的狀態(tài)以及被關(guān)注者的 ID。那么我們需要從 userInfo 中取出所需要的值:
let following = notification.userInfo["FollowingKey"] as! NSNumber let userID = notification.userInfo["UserIDKey"] as! NSNumber;
也就是說(shuō)接收通知的一方一般需要要查看文檔才知道怎樣從 userInfo 取值,取的值的類型又是什么。這對(duì)于使用是極為不方便的。
SwiftNotificationCenter
SwiftNotificationCenter是一種面向協(xié)議的通知中心方案。使用方式如下:
定義協(xié)議
protocol FollowingChanged { func followingDidChange(following: Bool, userID: NSNumber) }
基于協(xié)議注冊(cè)通知
Broadcaster.register(Update.self, observer: observer)
實(shí)現(xiàn)協(xié)議方法
extension ViewController: FollowingChanged { func followingDidChange(following: Bool, userID: NSNumber) { // do something } }
發(fā)送通知
Broadcaster.notify(FollowingChanged.self) { $0.followingDidChange(following, userID) }
移除注冊(cè)的通知
Broadcaster.unregister(Update.self, observer: observer)
我們可以看到,其基于協(xié)議的方式解決了弱類型的問(wèn)題,并且其通過(guò)AssociatedObject
實(shí)現(xiàn)了通知的自動(dòng)移除。但其也存在著擴(kuò)展性較差的問(wèn)題。
依然是關(guān)注改變的場(chǎng)景,假如隨著業(yè)務(wù)的發(fā)展,有的地方需要知道關(guān)注后是否為互關(guān)的狀態(tài),那么又需要增加一個(gè)字段來(lái)標(biāo)識(shí)。因此我們需要修改協(xié)議,增加參數(shù),且由于其不是必須傳遞的參數(shù),因此是 optional 類型。
protocol FollowingChanging { func followingDidChange(following: Bool, userID: NSNumber, followingEachOther: NSNumber?) }
如果在該類型通知被廣泛應(yīng)用的場(chǎng)景,那么需要修改的地方就尤其多了。這顯然也是難以接受的。
EventBus
EventBus 在安卓中被廣泛地應(yīng)用,其流程如下圖所示:
圖片來(lái)源:EventBus
使用方式如下:
定義事件
class TPFollowingChangedEvent: NSObject, TPEvent { private(set) var following: Bool private(set) var userID: NSNumber }
注冊(cè)事件
TPEventBus<TPFollowingChangedEvent>.shared.register(eventType: TPFollowingChangedEvent.self, subscriber: self, selector: #selector(onEvent(event:object:)))
實(shí)現(xiàn)監(jiān)聽(tīng)事件的方法
@objc func onEvent(event: TPFollowingChangedEvent, object: Any?) { // do something }
發(fā)送事件
TPEventBus.shared.post(event: event, object: self)
移除事件的注冊(cè)
TPEventBus<TPFollowingChangedEvent>.shared.unregister(eventType: TPFollowingChangedEvent.self, subscriber: self)
我們可以看到, EventBus 也是強(qiáng)類型的。
假如依然關(guān)注的場(chǎng)景,需要增加 followingEachOther 參數(shù),那么我們只需要在 TPFollowingChangedEvent 中增加 followingEachOther 參數(shù)即可。如下所示:
class TPFollowingChangedEvent: NSObject, TPEvent { private(set) var following: Bool private(set) var userID: NSNumber private(set) var followingEachOther: NSNumber? }
因此使用 EventBus 實(shí)現(xiàn)了以下需求:
- 強(qiáng)類型
- 可擴(kuò)展
EventBus 同 NotificationCenter 都是基于 target-action 的方案,但是我們不難將其擴(kuò)展為支持 block 監(jiān)聽(tīng)的方式,并且同樣讓其能夠自動(dòng)移除事件的注冊(cè)。類似于如下的使用方式:
TPEventBus<TPFollowingChangedEvent>.shared.subscribe(eventType: TPFollowingChangedEvent.self).forObject(self).onQueue(OperationQueue.main).onEvent { (event, object) in // do something }.disposed(by: self)
基于 OC, 我實(shí)現(xiàn)了一個(gè)小巧但比較全面的 EventBus 供參考:TPEventBus。
最后
我們可以看到,一對(duì)多場(chǎng)景中觀察者模式的應(yīng)用流程都大同小異,但是如何更好用確是值得深思的。當(dāng)然以上也只是我在一些使用場(chǎng)景上的思考,肯定會(huì)欠缺考慮,歡迎拍磚:blush:。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文)
欄 目:IOS
下一篇:iOS 13適配匯總(推薦)
本文標(biāo)題:詳解iOS中跨頁(yè)面狀態(tài)同步方案比較
本文地址:http://mengdiqiu.com.cn/a1/IOS/11868.html
您可能感興趣的文章
- 01-11iOS常用算法之兩個(gè)有序數(shù)組合并(要求時(shí)間復(fù)雜度為0(n))
- 01-11詳解MacOs免密登錄CentOs操作步驟
- 01-11iOS 彈幕功能的實(shí)現(xiàn)思路圖解
- 01-11iOS調(diào)試Block引用對(duì)象無(wú)法被釋放的小技巧分享
- 01-11iOS動(dòng)態(tài)更換Icon的全過(guò)程記錄
- 01-11iOS實(shí)現(xiàn)文本分頁(yè)的方法示例
- 01-11iOS常見(jiàn)宏理解及使用方法
- 01-11iOs遷至WKWebView跨過(guò)的一些坑
- 01-11iOS模擬中獎(jiǎng)名單循環(huán)滾動(dòng)效果
- 01-11Python一鍵查找iOS項(xiàng)目中未使用的圖片、音頻、視頻資源


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-11UILabel顯示定時(shí)器文本跳動(dòng)問(wèn)題的解決
- 01-11iOS常用算法之兩個(gè)有序數(shù)組合并(要
- 01-11iOS 彈幕功能的實(shí)現(xiàn)思路圖解
- 01-11詳解MacOs免密登錄CentOs操作步驟
- 01-11iOS動(dòng)態(tài)更換Icon的全過(guò)程記錄
- 01-11iOS調(diào)試Block引用對(duì)象無(wú)法被釋放的小技
- 01-11iOS常見(jiàn)宏理解及使用方法
- 01-11iOS實(shí)現(xiàn)文本分頁(yè)的方法示例
- 01-11iOs遷至WKWebView跨過(guò)的一些坑
- 01-11iOS模擬中獎(jiǎng)名單循環(huán)滾動(dòng)效果
隨機(jī)閱讀
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 04-02jquery與jsp,用jquery
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子