【API使用系列】Notification訊息通知專題
1 NSNotificationCenter機制
1.1 原理
1.1.1 不移除通知掛機原因分析
@implementation MRCObject
- (id)init
{
if (self = [super init]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(test) name:@"test"object:nil];
}
return self;
}
- (void)test
{
NSLog(@"=================");
}
- (void)dealloc
{
[super dealloc];
}
@end
在另一個類中引用:
- (void)viewDidLoad {
[superview DidLoad];
MRCObject *obj = [[MRCObjectalloc] init];
[obj release];
[[NSNotificationCenter defaultCenter] postNotificationName: @"test" object: nil];
}
在進入這個vc後,我們發現掛了。。
我們可以發現,向野指標物件傳送了訊息,所以掛掉了。從這點來看,蘋果實現也基本差不多是這樣的,只儲存了個物件的地址,並沒有在銷燬的時候置為nil。
這點就可以證明,addObserver後,必須要有remove操作。
1.1.2 ViewController中不手動移除通知不掛機原因分析
現在我們在UIViewController中註冊通知,不移除,看看會不會掛掉。
- (void)viewDidLoad {
[superviewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver: self selector:@selector(test) name: @"test" object: nil];
}
首先用navigationController進入到這個頁面,然後pop出去。最後點擊發送通知的按鈕事件:
- (void)didButtonClicked:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName: @"test" object: nil];
}
無論你怎麼點選這個按鈕,他就是不掛!這下,是不是很鬱悶了?我們可以找找看,你程式碼裡面沒有remove操作,但是NSNotificationCenter那邊已經移除了,不然肯定會出現上面野指標的問題。看來看去,也只能說明是UIViewController自己銷燬的時候幫我們暗地裡移除了。
那我們如何證明呢?由於我們看不到原始碼,所以也不知道有沒有呼叫。這個時候,我們可以從這個通知中心下手!!!怎麼下手呢?我只要證明UIViewController在銷燬的時候呼叫了remove方法,就可以證明我們的猜想是對的了!這個時候,就需要用到我們強大的類別這個特性了。我們為NSNotificationCenter添加個類別,重寫他的- (void)removeObserver:(id)observer方法:
- (void)removeObserver:(id)observer
{
NSLog(@"====%@
remove===", [observer class]);
}
這樣在我們VC中匯入這個類別,然後pop出來,看看發生了什麼!
2015-01-19 22:59:00.580 測試[1181:288728] ====TestViewController remove===
怎麼樣?是不是可以證明系統的UIViewController在銷燬的時候呼叫了這個方法。(不建議大家在開發的時候用類別的方式覆蓋原有的方法,由於類別方法具有更高的優先權,所以有可能影響到其他地方。這裡只是除錯用)。
以上也提醒我們,在你不是銷燬的時候,千萬不要直接呼叫[[NSNotificationCenter
defaultCenter] removeObserver: self]; 這個方法,因為你有可能移除了系統註冊的通知。
1.1.3 多執行緒通知
首先看下蘋果的官方說明:
Regular notification centers deliver notifications on the thread in which the notification was posted. Distributed notification centers deliver notifications on the main thread. At times, you may require notifications to be delivered on a particular thread that is determined by you instead of the notification center. For example, if an object running in a background thread is listening for notifications from the user interface, such as a window closing, you would like to receive the notifications in the background thread instead of the main thread. In these cases, you must capture the notifications as they are delivered on the default thread and redirect them to the appropriate thread.
意思很簡單,NSNotificationCenter訊息的接受執行緒是基於傳送訊息的執行緒的。也就是同步的,因此,有時候,你傳送的訊息可能不在主執行緒,而大家都知道操作UI必須在主執行緒,不然會出現不響應的情況。所以,在你收到訊息通知的時候,注意選擇你要執行的執行緒。下面看個示例程式碼
//接受訊息通知的回撥
- (void)test
{
if ([[NSThreadcurrentThread] isMainThread]) {
NSLog(@"main");
}else{
NSLog(@"not main");
}
dispatch_async(dispatch_get_main_queue(), ^{
//do your UI
});
}
//傳送訊息的執行緒
- (void)sendNotification
{
dispatch_queue_t defaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(defaultQueue, ^{
[[NSNotificationCenter defaultCenter] postNotificationName: @"test" object: nil];
});
}
2 開發技巧
2.1 常用開發技巧
2.1.1 注意重複addObserver
在我們開發中,我們經常可以看到這樣的程式碼:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear: animated];
[[NSNotificationCenter defaultCenter] addObserver: self selector:@selector(test) name: @"test" object: nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear :animated];
[[NSNotificationCenter defaultCenter] removeObserver: self name:@"test" object: nil];
}
就是在頁面出現的時候註冊通知,頁面消失時移除通知。你這邊可要注意了,一定要成雙成對出現,如果你只在viewWillAppear 中 addObserver沒有在viewWillDisappear 中 removeObserver那麼當訊息發生的時候,你的方法會被呼叫多次,這點必須牢記在心。
3 參考連結
iOS NSNotificationCenter使用姿勢詳解
相關推薦
【API使用系列】Notification訊息通知專題
1 NSNotificationCenter機制1.1 原理1.1.1 不移除通知掛機原因分析@implementation MRCObject- (id)init{ if (self = [super init]) { [[NSNotificationC
【圖文詳細 】Kafka訊息佇列——Kafka 的各種 API 操作
7.1、Kafka 的 API 分類 1、The Producer API 允許一個應用程式釋出一串流式的資料到一個或者多個 Kafka Topic。 2、The Consumer API 允許一個應用程式訂閱一個或多個 Topi
【ZooKeeper系列】2.用Java實現ZooKeeper API的呼叫
溫馨提示:在這裡我再次提個小要求,希望大家能習慣看官方文件,文件雖然是英文但用詞都比較簡單,基本都能看懂文件表達的意思。授之以魚不如授之以漁的道理相信大家都明白,也希望通過猿人谷的這個ZooKeeper系列,讓大家入門、到熟悉,舉一反三後能精通ZooKeeper。 在前一篇我們介紹了ZooKeeper單機
【Gin-API系列】配置檔案和資料庫操作(三)
我們前面已經實現了API的基礎版本,能對引數校驗和返回指定資料,這一章,我們將對主機和交換機進行建模,存入資料庫。 考慮到資料庫安裝和使用的簡便性,我們採用文件儲存結構的MongoDB資料庫。 > Mongo資料庫下載安裝,安裝後不用設定密碼,直接使用即可 下載連結 [https://www.file
【Gin-API系列】Gin中介軟體之日誌模組(四)
日誌是程式開發中必不可少的模組,同時也是日常運維定位故障的最重要環節之一。一般日誌類的操作包括日誌採集,日誌查詢,日誌監控、日誌統計等等。本文,我們將介紹日誌模組在Gin中的使用。 ## Golang如何列印日誌 * 日誌列印需要滿足幾個條件 1. 重定向到日誌檔案 2. 區分日誌級別,一般有`DEBUG`,
【Gin-API系列】Gin中介軟體之鑑權訪問(五)
在完成中介軟體的介紹和日誌中介軟體的程式碼後,我們的程式已經基本能正常跑通了,但如果要上生產,還少了一些必要的功能,例如鑑權、異常捕捉等。本章我們介紹如何編寫鑑權中介軟體。 > 鑑權訪問,說白了就是給使用者的請求增加一些限制條件,過濾掉不符合要求的請求。完善的鑑權模組可以讓我們的服務跑得更加安全,特別
【Gin-API系列】Gin中介軟體之異常處理(六)
本文我們介紹生產環境上如何通過捕捉異常`recovery`來完善程式設計和提高使用者體驗。 # Golang異常處理 > golang 的異常處理比較簡單,通常都是在程式遇到異常崩潰`panic`之後通過`defer`呼叫延遲函式捕捉異常,並對異常資訊進行輸出和記錄。 * 異常處理程式碼 ```gol
【Gin-API系列】實現動態路由分組(七)
在之前的文章介紹中我們已經完成了一個API服務的全鏈路請求設計。呼叫方式可以看Test目錄的程式碼 ```golang // src/test/request_test.go func TestAPI_Request(t *testing.T) { url := "127.0.0.1:8080" ak :
【Gin-API系列】守護程序和平滑重啟(八)
生產環境的API服務我們都會部署在Linux伺服器上,為了不受終端狀態的影響,啟動服務的時候會讓服務在後臺執行。那麼如何讓服務在後臺執行呢,目前有2種常見的方法。 ### 1、nohub 執行 表示忽略`SIGHUP`(結束通話)訊號,終端退出的時候所發起的結束通話訊號會被忽略。`nohup`一般會結合`&a
【Gin-API系列】部署和監控(九)
本文是【Gin-API系列】的最後一篇文章,簡單介紹如何在生產環境的部署架構和監控手段。 # 生產部署 * 部署架構 > 使用`Nginx`加`Keepalived`的方式搭建,可以達到高可用的效果,並可以橫向擴容 ![部署架構圖](https://img2020.cnblogs.com/blog/5
【linux系列】vmware12pro安裝centos7
ping entos 配置 行編輯 rip 無法 conf 解決 config 安裝參考:http://blog.csdn.net/guin_guo/article/details/49403889 安裝完成之後ip還是不成功無法連接網絡: 進入/etc/sysconfig
【Yii系列】處理請求
入口 實現 官方 cookie this sender att 只需要 ota 緣起 這一章是Yii系列的第三章,前兩章給大夥講解了Yii2.0的安裝與Yii2.0的基本框架及基礎概念,傳送門: 【Yii2.0的安裝與調試】:http://www.cnblogs.com/r
【CNMP系列】CentOS7.0下安裝Nginx服務
系統資源 for proxy input strong network emc -c .com 話步前言,CNMP之路,系統起步:http://www.cnblogs.com/riverdubu/p/6425028.html 這回我來講解下CentOS7.0下如何安裝和配置
【CNMP系列】CNMP之路,系統起步。
ftp 系列 fig samba 建立連接 編輯 為我 作用 let 簡單的來理解,我所說的CNMP,不是CNM+P,而是CentOs+Nginx+MySql+PHP,也可以單純的理解為LNMP,但是系統是我們自己選的,雖說是Linux的一個分支,但我就喜歡CentOs的這
【PHP系列】PHP組件詳解
命令行 分享 .cn .com function package etc quest 說我 緣起 楓爺之前做過幾年的PHP的研發,大部分都是在開源框架的引導下,編寫代碼。現在依然,本能的會去讓我使用某個PHP框架開發PHP應用,也是因為懶吧,沒有好好的去研究研究除了框架之外
【HLSDK系列】服務端 UpdateClientData 函數
del 完全 dll viewmodel 代碼 lag ase mod water 首先說明下,這個函數是寫在 mp.dll 裏的。 服務器會給每個客戶端發送一些數據,其中兩大數據種類就是 clientdata_t 和 entity_state_t 這裏要說的是 clien
【HLSDK系列】服務端 AddToFullPack 函數
客戶端 global 客戶 const start max pre 參數 glob 服務端會給客戶端發送一些數據,其中兩大種類數據是 clientdata_t 和 entity_state_t 這裏我們說說 entity_state_t 這個結構體。 你在丟在地上的槍、C4
【HLSDK系列】怎麽增加一種新實體
sta fun class 使用 pen 關聯 creat bsp cnblogs 你平常肯定接觸到很多比如 info_player_start hostage info_target 之類的實體,這裏就解釋一下怎麽創建一種新的實體。 首先建立一個新的 .h 文件(當然你寫
【HLSDK系列】HL引擎入門篇
入門 理解 我的文章 模塊 兩個 工作 什麽 服務端 為我 如果你打算拿HL的源碼(也就是HLSDK)來改出一個自己的遊戲,那你就非常有必要理解一些HL引擎的工作方式。 HL引擎分成兩個部分,服務端和客戶端。服務端管理所有玩家的狀態和遊戲規則,客戶端負責顯示UI和特效…之類
【HLSDK系列】服務端實體 edict_t 和 控制類
武器 .cpp 成員 常用 blog 生成 指針 但是 dll 我們來了解一下引擎是怎麽管理實體的吧!我們這裏就說說服務端的實體(edict_t) 服務端用 edict_t 這個結構體來保存一個實體,可以說一個 edict_t 就是一個 服務端實體,下文簡稱實體。 我們在