NotificationCenter
是基于iOS程序內(nèi)部之間的一種消息廣播機(jī)制,主要是為了解決應(yīng)用程序不同對(duì)象之間通信解藕而設(shè)計(jì)。它基于KVO
模式設(shè)計(jì),當(dāng)收到通知后由通知中心根據(jù)轉(zhuǎn)發(fā)表將消息發(fā)給觀察者。
在Apple的文檔里面有如下說明:
A notification center delivers notifications to observers synchronously. In other words, when posting a notification, control does not return to the poster until all observers have received and processed the notification. To send notifications asynchronously use a notification queue, which is described in Notification Queues.
In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself.
其實(shí)它主要是指NotificationCenter
是一種“同步的”消息機(jī)制,當(dāng)一個(gè)通知被post之后,他將會(huì)在所有的觀察者都完成了對(duì)應(yīng)的方法后才會(huì)返回。在多線程的應(yīng)用中,通知是在哪個(gè)線程Post就在哪個(gè)線程分發(fā),也就是在同一個(gè)線程被觀察者處理,所以觀察者的回調(diào)函數(shù)是完全由發(fā)送消息的線程決定,而不是由注冊(cè)時(shí)所在的線程決定。
關(guān)于這一點(diǎn)我舉一下我在對(duì)聊天消息進(jìn)行優(yōu)化的時(shí)候發(fā)現(xiàn)的問題作為例子,在原來的代碼結(jié)構(gòu)中,需要處理獲取的消息,并更新會(huì)話cell的排序:
swift
ConversationModel.swift
func handleMessage() {
var message = Message()
/* do something to create and process messages */
NotificationCenter.default.post(name: NSNotification.Name(rawValue: kRefreshConversation), object: self)
}
ConversationVC.swift
func viewDidLoad() {
NotificationCenter.default.addObserver(self, selector: #selector(refreshConversatin(_:)), name: NSNotification.Name(rawValue: kRefreshConversation), object: nil)
/* other things ...*/
}
@objc private func refreshConversatin(_ noti: Notification) {
/* use a long time to sort conversation */
tableview.reloadData()
}
在原來這種處理方式中,由于refreshConversation
這個(gè)方法會(huì)耗費(fèi)大量時(shí)間,而這個(gè)通知是在主線程發(fā)起的,所以會(huì)導(dǎo)致主線程被阻塞,所以我針對(duì)這個(gè)問題對(duì)ConversationModel
進(jìn)行了重構(gòu)。
首先我將Conversation獲取并組裝Message的這一塊內(nèi)容都放置在后臺(tái)線程進(jìn)行,因?yàn)镸odel相關(guān)的操作可能會(huì)占用很多的時(shí)間,放在主線程創(chuàng)建并組裝是不可靠的。當(dāng)message組裝完畢需要更新ConversationVC
中的排序時(shí),在ConversationVC
中接收到通知后再轉(zhuǎn)到主線程進(jìn)行操作。同時(shí)我在排序的代碼中也進(jìn)行了優(yōu)化,如果ConversationVC
沒有被展示的話,就不需要占用主線程調(diào)用tableView
的tableView.insertRows
方法,僅僅需要在后臺(tái)線程中對(duì)ConversationModel
的數(shù)組進(jìn)行排序即可。因?yàn)?code>tableView.insertRows會(huì)占用大量主線程時(shí)間,所以減少使用該方法的頻率,只在必要時(shí)候調(diào)用,將排序等操作放到后臺(tái)線程進(jìn)行是比較好的解決方法。
想了解更多內(nèi)容可以查看我的博客