[英]NSNotificationCenter posting notifications doesn't work
我有一個使用nw_path_monitor_t注冊網絡事件的 func。
// Entry point.
// Will be called from AppDelegate when app starts up
void TestNWPathMonitor () {
PrintToFile("TestingNWPathMonitor\n");
NotificationReceiver *notification_receiver = [[NotificationReceiver alloc] init];
// Set up the notification receiver to listen for wifi notification
[notification_receiver RegisterNotification];
monitor = nw_path_monitor_create ();
nw_path_monitor_set_update_handler (monitor, WifiNetworkChangeCB);
nw_path_monitor_start(monitor);
}
我已經提供了回調,它將在網絡事件發生變化時被調用。 在回調中(如下所示),我正在尋找 wifi 事件並向默認通知中心發布通知。
nw_path_monitor_update_handler_t WifiNetworkChangeCB = ^ (nw_path_t path) {
PrintToFile("Wifi Network change!!\n");
nw_path_status_t status = nw_path_get_status (path);
if (nw_path_uses_interface_type (path, nw_interface_type_wifi)) {
if (status == nw_path_status_satisfied) {
PrintToFile("nw_path_status_satisfied\n");
[[NSNotificationCenter defaultCenter] postNotificationName:@"WifiNetworkChange" object:nil];
} else {
PrintToFile("!(nw_path_status_satisfied)\n");
}
}
};
這是 NotificationReceiver 類:
// NotificationReceiver.h
#include <Foundation/Foundation.h>
@interface NotificationReceiver : NSObject
- (void) HandleNotification : (NSNotification *) pNotification;
- (void) RegisterNotification ;
@end
// NotificaitonReceiver.m
@implementation NotificationReceiver
- (void) HandleNotification : (NSNotification *) pNotification {
PrintToFile([[NSString stringWithFormat:@"Received notification: %@\n", pNotification.name] UTF8String]);
}
- (void) RegisterNotification {
PrintToFile("RegisterNotification!\n");
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(HandleNotification:) name:@"WifiNetworkChange" object:nil];
}
@end
在開始時調用的 RegisterNotification(如第一個代碼片段所示)將添加該實例作為觀察者,而 HandleNotification 是從 WifiNetworkChangeCB 塊發布的 wifi 通知的接收者。
問題是,當我收到 wifi 事件時,會調用WifiNetworkChangeCB並執行postNotificationName函數(已與調試器驗證),但 HandleNotification 未收到通知。
我得到以下輸出:
TestingNWPathMonitor
RegisterNotification!
Wifi Network change!!
而預期的輸出是:
TestingNWPathMonitor
RegisterNotification!
Wifi Network change!!
Received notification: WifiNetworkChange
我已閱讀通知中心的文檔以了解其用法。 也提到了這個答案。 我還參考了我正在使用的 funcs 的文檔(在解釋問題時將它們添加為超鏈接),一切似乎都很好。
但我顯然錯過了一些東西(因為它不起作用)。 任何幫助將不勝感激。
原因:您的 C 函數TestNWPathMonitor()
分配NotificationReceiver *notification_receiver
但是當您離開范圍時,創建的對象沒有存儲在任何地方。 因此,使用 ARC 內存管理,當作用域塊離開時,對象將被釋放,也就是它的堆棧再次“空”。
你的monitor
又名typedef NSObject<OS_nw_path_monitor> *nw_path_monitor_t;
似乎是全局的,因此在離開范圍后它仍然存在,這可能會給您帶來誤解,即 objc 分配也是如此,是和否。 同樣的情況也有happend到顯示器,如果它本來是一個局部變量。
調試:觀察[NSNotificationCenter defaultCenter]
允許您在代碼中的幾乎任何地方捕獲通知,無論您等待它們的線程是什么,它是一個基於 NSString 的 API ,其優點和缺點都有充分的理由。 由於這種簡單的方法,很難找到它不起作用的原因。 但基本上在main.m
或APPDelegate
放置一個 Observer 應該總是告訴你它是否在發布端正常工作,以確保你沒有APPDelegate
NotificationName
。 為了避免后一種情況,我們經常聲明
extern NotificationName const kSomeNiceNotification;
// in .h && the following in .m
NotificationName const kSomeNiceNotification = @"kSomeNiceNotification";
並使用此全局鍵作為名稱。
提示:您還可以創建一個單一的通知,該通知將在收到時觸發並銷毀自身,並在執行此操作時必須考慮其他含義。 像這樣(來自 Xcode 文檔)。
NSNotificationCenter * __weak center = [NSNotificationCenter defaultCenter];
id __block token = [center addObserverForName:@"OneTimeNotification"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
NSLog(@"Received the notification!");
[center removeObserver:token];
}];
看到上面代碼片段中的[NSOperationQueue mainQueue]
了嗎? 您可以在那里傳遞nil
,但是通知塊將在發送通知的線程上執行。 當在 UI 代碼中使用時,這通常是通知的用例,這很重要,因為 UI 任務需要在主線程上執行,在主線程中傳遞nil
迫使您稍后將 UI 內容包裝在
dispatch_async(dispatch_get_main_queue(), ^{ /* UI code block */ }); // or
dispatch_sync(dispatch_get_main_queue(), ^{ /* UI code block */ });
當您告訴通知觀察者在收到通知塊時執行通知塊的位置時,您不需要這樣做。
Ps:在objc中我們以小寫字母開頭methodnames,當setter和getter違反“camelCased”methodname規則時,你會遇到麻煩,因為接口@property NSObject *someName;
變成-(NSObject*)someName;
作為 getter 和-(void)setSomeName:(NSObject*)somename;
作為現代 objc 的二傳手。 這也說明了為什么我們使用較低的下划線來標記幾乎所有屬性對應的局部類變量..在這個給定的示例中,屬性NSObject *someName
將具有內部_someName
對應。 這里不會像在 oldschool objc 中那樣深入,有更多關於類聲明@dynamic ...
& @synthesize ...
了解,這些聲明允許更詳細地控制(內部)本地類變量名稱。
為什么要為此煩惱? 您的NotificationReceiver *notification_receiver
可以覆蓋具有相同名稱的類屬性,給您的印象是您所做的一切都正確,但仍然無法正常工作,因為聲明仍然會使堆棧為空。 因此,在方法/功能塊中聲明像_notification_receiver = ...
這樣的變量會很清楚你的意思是它的內部對應物@property NotificationReceiver *notification_receiver;
而不是額外的局部變量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.