NSNotification,NSNotificationCenter的使用、iOS中五種對象間傳值的方式
學習內容
NSNitification與NotificationCenter(通知與通知中心)
-
通知的使用
-
[[NSNotificationCenter defaultCenter]addObserver:selfselector:@selector (noticeAction:) name:@"name" object:nil];
註冊觀察者
-
NSNotification* notice = [NSNotification notificationWithName:@"name" object:nil userInfo:params]; [[NSNotificationCenter defaultCenter]postNotification:notice];
創建一個通知並發送
-
觀察者對象的註冊一定要比通知的發送提前,否則的話會接收不到通知
-
-
通知和delegate的基本區別
- 通知是允許多對多的,而delegate只能是一對一的
- 通知的耦合度較低,發送方不需要知道通知方的任何情況,而delegate不行
- 通知的效率比起delegate略差
-
通知是同步還是非同步的?
- postNotification:通知的發送總是會卡住當前執行緒,等待所有的observer對象執行(如果沒有經過特殊處理,接收者對象的selector與postNotification在同一執行緒執行)完成後才會繼續往下執行,所以是同步的
-
通知的移除
- 在iOS9之前的版本中,如果對一個觀察者對象在delloc之前之中沒有從通知中心移除(remove)的話,會產生BAD_ACCESS野指針錯誤,導致crash
- iOS9.0及以後的版本中不會造成crash
- 原因:iOS9.0之前NSNotificationCenter持有的是observer的unsafe_uncertain指針,如果觀察者對象已經被釋放,但是沒有從通知中心移除,那麼postNotification方法會向觀察者已經被回收的記憶體發送消息,就會造成野指針訪問錯誤,iOS9.0以後,系統將unsafe_uncertain指針更改成了weak指針(對象回收,自動置nil),向nil發送消息不會差生任何問題(同時這裡說明了oc是可以向nil發送消息的)
-
非同步通知
-
[[NSNotificationQueue defaultQueue]enqueueNotification:notice postingStyle:NSPostASAP]; ----------------------------------------------------------------------------------typedef NS_ENUM(NSUInteger, NSPostingStyle) { //空閑發送通知 當運行循環處於等待或空閑狀態時,發送通知,對於不重要的通知可以使用。 NSPostWhenIdle = 1, //儘快發送通知 當前運行循環迭代完成時,通知將會被發送,有點類似沒有延遲的定時器。 NSPostASAP = 2, //和postNotification一樣是同步通知 NSPostNow = 3 };
-
三種枚舉類型代表三種發送方式(非同步/同步都可)
-
同樣的,非同步發送通知的話還可以使用開啟一個新的執行緒的方式
-
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [[NSNotificationCenter defaultCenter]postNotification:notice]; });
-
-
通知的合併(待完善)
-
[[NSNotificationQueue defaultQueue] enqueueNotification:notice postingStyle:NSPostASAP coalesceMask:NSNotificationNoCoalescing forModes:nil]; ----------------------------------------------------------------------------------- typedef NS_OPTIONS(NSUInteger, NSNotificationCoalescing) { // 不合成 NSNotificationNoCoalescing = 0, // 根據NSNotification的name欄位進行合成 NSNotificationCoalescingOnName = 1, // 根據NSNotification的object欄位進行合成 NSNotificationCoalescingOnSender = 2 };
-
NSNotificationQueue除了有非同步通知的能力之外,也能對當前隊列的通知根據NSNotificationCoalescing類型進行合併,需要配合不同的NSRunLoopMode來進行
-
通過合併通知我們可以用來保證相同的通知只被發送一次
-
-
NSNotificationCenter實現原理
- 通知中心用來管理通知的接收和發送,一開始將觀察者註冊到通知中心的通知調度表中,然後發送通知時利用標識符name和object識別出觀察者,並調用相應的觀察者方法,即傳遞消息(消息傳遞機制),如果是基於block創建的通知就調用NSNitification的block
-
NSNotificationCenter使用block方式添加的觀察者
-
- (id<NSObject>)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block
-
addObserver使用一個現存的對象作為觀察者(一般為self),而使用block方法會創建一個匿名的(id
)對象作為觀察者,這個匿名對象會在指定的隊列上去執行block -
如果
queue
為nil,則消息是默認在post
執行緒中同步處理,即通知的post
與轉發是在同一執行緒中,不為nil的話就會在我們指定的隊列中執行 -
如果一個給定的通知觸發了多個觀察者的
block
操作,則這些操作會在各自的Operation Queue
中被並發執行。所以我們不能去假設操作的執行會按照添加觀察者的順序來執行 -
這個方法會返回一個匿名的觀察者對象,我們需要手動釋放這個對象。
-
iOS中對象間的五種傳值方式(屬性、代理、單例、Block、通知)
-
屬性傳值
- 通過對象的公有屬性進行傳值
-
代理傳值
-
在委託方定義協議,協議中聲明@required/@optional方法,聲明一個代理屬性,使用weak修飾符
-
在代理方遵守協議,實現協議中的方法
-
初始化委託對象,將委託對象的代理設置為self(代理對象自身)
-
查看代理方是否實現了需要執行的選擇子(SEL),如果實現了便開始執行
-
if ([self.delegate respondsToSelector:@selector(codeIOS)]) { // 讓代理方執行協議中的方法 [self.delegate SEL]; }
-
代理傳值一般用於逆向傳值,如:A控制器跳轉到B控制器,B控制器為委託對象,A控制器為代理對象,B對象的代理為A對象,那麼在B對象中可以傳值給A對象,並在A對象中執行相應的方法
-
-
單例模式傳值
- 將一個類寫成單例(常用dispatch_once),這樣這個類就只含有全局唯一的實例,可以向整個程式提供實例
- 如果一個類創建實例會耗費很多資源,那麼可以將這個類寫成單例類,節省alloc,init的時間
- 在程式中如果多個類訪問同一個變數,那麼也可以將將該變數寫入單例類中,調用起來更加方便
-
使用block程式碼塊進行傳值
-
可以用於數據在多個對象間傳遞,網路請求的回調等
-
//在對象B中block作為方法參數 - (void)getNextPage:(void (^)(BOOL))completeBlock{ //block可以嵌套,第一層block可以在最後的block體中進行回調 [self getPage:self.page complete:^(NSMutableArray *result) { if ([result count]) { self.page++; [self.musicList addObjectsFromArray:result]; if (completeBlock) { //需要回調時,執行block completeBlock(true); } }else{ if (completeBlock) { completeBlock(false); } } }]; } ------------------------------------------------------------------------------ //在對象A中isSucceed為回調回來的值 [strongSelf.musicModel getNextPage:^(BOOL isSucceed) { if (isSucceed) { [strongSelf.waterFallCollectionView reloadData]; } }];
-
-
通知傳值
- NSNotification的使用就是通知傳值的一些用法