iOS 趣談設計模式——通知,ios趣談設計模式
【前言介紹】
iOS的一種設計模式,觀察者Observer模式(也叫發布/訂閱,即Publich/Subscribe模式)。
觀察者模式,包含了通知機制(notification)和KVO(Key-value-observing)機制。
在這本文中,我們將介紹在日常項目當中經常使用到的通知機制這一種設計模式。
通知機制
委託機制是代理“一對一”的對象之間的通訊,而通知機制是廣播“一對多”的對象之間的通訊;
一、是什嗎?【生活問題例子】
“簡訊天氣預報”
當A類發送一條資訊給通知中樞時,註冊為使用者(觀察者)的B類群就會收到相應的通知,並作出反應。
二、有什麼用?【代碼中的應用】
在不同類之間如何傳遞資料?
有幾種方法:屬性傳遞、代理協議,另外就是通知。
通知:在A類中建立的方法,B類中執行,且可以使用該通知攜帶資料傳遞給對方;
三、有什麼不同?【與其他“通知”的不同?】
經常提到的通知,有“廣播通知”、“本地通知”、“推播通知”
本文所介紹的就是廣播通知,是實現觀察者模式的一種機制,可以在一個應用中的多個對象之間進行通訊傳遞資料。
而本地通知和推播通知主要是給使用者發送“通知提示”,例如警告提示、聲音、震動以及標上的紅色數字提示。
第一種由“本地發送通知”給使用者,第二種由第三方應用發送給蘋果官方的遠程伺服器,然後再由伺服器“推播通知”給使用者。
四、產品經理:老規矩,代碼拿來~【具體實現】
過程:
- 在通知機制中,需要(或者說感興趣)接收某個通知的資訊的所有對象都可以成為接收者,首先註冊成為觀察者。
- 進行註冊後,通知中樞就會把發行者發送的通知資訊,廣播給註冊過該通知的觀察者。且觀察者只能接收到通知中樞的資訊,不能知道通知是誰投送的。
- 最後,接受者不想再對關注該通知的資訊時,可以給通知中樞發生解除註冊的資訊,之後都不再接收到通知了。
1.擷取通知中樞(NSNotificationCenter)對象:(就像擷取移動營運商簡訊中心的許可權,作為媒介)
發布、註冊、解除通知都需要使用通知中樞,負責協助不同對象、不同類之間的訊息通訊。
[NSNotificationCenter defaultCenter]; //需要注意的是,通知中樞也是一個單例
2.發布(A類)和接收(B類)
a.做為發行者的A類發送通知:
可以使用一下三個方法:
- (void)postNotification:(NSNotification *)notification;- (void)postNotificationName:(NSString *)aName object:(id)anObject;- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
- postNotificationName:指定訊息名稱;
- object:指定發訊息者;
- userInfo:通知中用於傳遞參數的載體,傳遞的方法是把參數放在NSDictionary類型的userInfo中。例如:NSDictionary *dict = [notification userInfo];
一般使用第三個方法,如果參數不需要的,可以設定為nil.
b.註冊通知,加入觀察者:
做為觀察者B類註冊通知,進行監聽:
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject;
//@selector中為回調方法,在本類中對通知進行相應的處理,name為通知名稱、object為對象;
剖析:
- object == nil,那麼客戶對象(self)將收到任何對象發出NSWindowDidBecomeMainNotification的通知訊息;
- name == nil,那麼觀察者將接收到object對象的所有訊息,但是確定不了接收這些訊息的順序。
- object == nil,name == nil,那麼該觀察者將收到所有對象的所有訊息。
對於一個任意的觀察者observer,如果不能保證其對應的selector有本類自訂的方法(例如:MyMethod),可採用[observer respondsToSelector:@selector(MyMethod:)]] 進行檢查。
所以完整的添加觀察者過程為:
if([observer respondsToSelector:@selector(MyMethod:)]) { [[NSNotificationCenter defaultCenter] addObserver:observer selector:@selector(MyMethod:) name:NSWindowDidBecomeMainNotification object:nil]; }
當然在蘋果API中也有另外一個註冊觀察者的方法:
- (id <NSObject>)addObserverForName:(nullable NSString *)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block
此方法是支援在該方法中進行block回調的,而queue參數就是表示此模組在queue隊列中進行。
但是這方法一般不採用,所以建議使用第一種方法進行觀察者的建立。
c.移除通知
由於通知中樞不會retain觀察者對象,因此註冊過的對象必須在釋放之前登出掉,如果不這樣的話,當該通知再次出現時,通知中樞會向已釋放的觀察者對象發送訊息,從而導致應用崩潰。
在ARC下,系統會自動回收無用的通知對象記憶體,但是由於系統回收機制ARC有一定的延遲性,所以即使不會出錯,也建議養成習慣,對通知進行手動釋放無用的通知。
移除有2種方法:
//釋放所有通知
- (void)removeObserver:(id)observer;
//釋放名稱為aName的通知- (void)removeObserver:(id)observer name:(nullable NSString *)aName object:(nullable id)anObject;
一般在視圖控制器中,可以在“didReceiveMemoryWarning:”中發送解除訊息:
-(void)didReceiveMemoryWarning{ [super didReceiveMemoryWarning]; //移除觀察者 [[NSNotificationCenter defaultCenter]removeObserver:self];}
五、那些年我們用過的系統通知名稱~
系統內建的也有許多有用的通知,我們只需要註冊為相應的通知接收對象,就能根據通知狀態的變化發生相應的資料改變。
部分系統通知名稱如下:
UIApplicationDidFinishLaunchingNotification // 應用程式啟動後UIApplicationDidBecomActiveNotification //進入前台 UIApplicationWillResignActiveNotification //應用將要進入後台
UIApplicationDidEnterBackgroundNotification //進入後台UIKeyboardWillShowNotification // 鍵盤即將顯示 UIKeyboardDidShowNotification // 鍵盤顯示完畢 UIKeyboardWillHideNotification // 鍵盤即將隱藏 UIKeyboardDidHideNotification // 鍵盤隱藏完畢
六、舉個栗子:“