簡體   English   中英

NSNotificationCenter 發布通知不起作用

[英]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.mAPPDelegate放置一個 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM