給通知和KVO添加block實(shí)現(xiàn)

給通知和KVO添加block實(shí)現(xiàn)

給通知添加block的實(shí)現(xiàn)

  1. 創(chuàng)建NSObject分類并創(chuàng)建分類方法(帶通知名參數(shù)和block回調(diào)參數(shù))
  if (!name || !block) return;
    dispatch_semaphore_t notificationSemaphore = [self _xw_getSemaphoreWithKey:XWNotificationSemaphoreKey];
    dispatch_semaphore_wait(notificationSemaphore, DISPATCH_TIME_FOREVER);
    NSMutableDictionary *allTargets = objc_getAssociatedObject(self, XWNotificationBlockKey);
    if (!allTargets) {
        allTargets = @{}.mutableCopy;
        objc_setAssociatedObject(self, XWNotificationBlockKey, allTargets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    _XWBlockTarget *target = allTargets[name];
    if (!target) {
        target = [_XWBlockTarget new];
        allTargets[name] = target;
        [[NSNotificationCenter defaultCenter] addObserver:target selector:@selector(xw_doNotification:) name:name object:nil];
    }
    [target xw_addNotificationBlock:block];
    [self _xw_swizzleDealloc];
    dispatch_semaphore_signal(notificationSemaphore);

如果通知名為空或者block為空直接返回,調(diào)用懶加載方法_xw_getSemaphoreWithKey獲取信號(hào)量對(duì)象,信號(hào)量等待,懶加載獲取關(guān)聯(lián)屬性targets字典,從targets字典中取出對(duì)應(yīng)通知名的target對(duì)象(如果沒(méi)有就創(chuàng)建一個(gè),并保存到字典中,將給系統(tǒng)的通知中心注冊(cè)observer為target的通知,執(zhí)行方法為target中的方法,target的方法中調(diào)用block),通知中心添加對(duì)應(yīng)的通知名的通知,target的blockset添加對(duì)應(yīng)的block
當(dāng)調(diào)用分類的發(fā)送通知的方法的時(shí)候,利用系統(tǒng)的通知中心發(fā)送通知,target對(duì)象的就能收到通知,target對(duì)象調(diào)用block,分類中注冊(cè)通知方法中的block被調(diào)用,完成回調(diào)

給KVO添加block回調(diào)的實(shí)現(xiàn)

調(diào)用分類的addObserver方法,懶加載創(chuàng)建信號(hào)量,信號(hào)量等待,通過(guò)關(guān)聯(lián)屬性方法獲取block字典,如果沒(méi)有分類關(guān)聯(lián)屬性,則創(chuàng)建并設(shè)置關(guān)聯(lián)屬性,通過(guò)可以path從關(guān)聯(lián)屬性字典中獲取到target,如果target為空則創(chuàng)建target對(duì)象,并將target對(duì)象保存到字典,將target對(duì)象設(shè)置為本方法調(diào)用者的監(jiān)聽(tīng)也就是調(diào)用addObserver方法。路徑為keypath,如果target對(duì)象存在則直接給target對(duì)象的block數(shù)組中添加block。發(fā)送信號(hào),取消信號(hào)量限制。

- (void)xw_addObserverBlockForKeyPath:(NSString*)keyPath block:(void (^)(id obj, id oldVal, id newVal))block {
   if (!keyPath || !block) return;
   dispatch_semaphore_t kvoSemaphore = [self _xw_getSemaphoreWithKey:XWKVOSemaphoreKey];
   dispatch_semaphore_wait(kvoSemaphore, DISPATCH_TIME_FOREVER);
   //取出存有所有KVOTarget的字典
   NSMutableDictionary *allTargets = objc_getAssociatedObject(self, XWKVOBlockKey);
   if (!allTargets) {
       //沒(méi)有則創(chuàng)建
       allTargets = [NSMutableDictionary new];
       //綁定在該對(duì)象中
       objc_setAssociatedObject(self, XWKVOBlockKey, allTargets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
   }
   //獲取對(duì)應(yīng)keyPath中的所有target
   _XWBlockTarget *targetForKeyPath = allTargets[keyPath];
   if (!targetForKeyPath) {
       //沒(méi)有則創(chuàng)建
       targetForKeyPath = [_XWBlockTarget new];
       //保存
       allTargets[keyPath] = targetForKeyPath;
       //如果第一次,則注冊(cè)對(duì)keyPath的KVO監(jiān)聽(tīng)
       [self addObserver:targetForKeyPath forKeyPath:keyPath options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
   }
   [targetForKeyPath xw_addBlock:block];
   //對(duì)第一次注冊(cè)KVO的類進(jìn)行dealloc方法調(diào)劑
   [self _xw_swizzleDealloc];
   dispatch_semaphore_signal(kvoSemaphore);
}

target對(duì)象實(shí)現(xiàn)observer代理方法,當(dāng)觀察的keypath發(fā)生變化的時(shí)候,target枚舉自己block數(shù)組中的block并一一調(diào)用。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
   if (!_kvoBlockSet.count) return;
   BOOL prior = [[change objectForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue];
   //只接受值改變時(shí)的消息
   if (prior) return;
   NSKeyValueChange changeKind = [[change objectForKey:NSKeyValueChangeKindKey] integerValue];
   if (changeKind != NSKeyValueChangeSetting) return;
   id oldVal = [change objectForKey:NSKeyValueChangeOldKey];
   if (oldVal == [NSNull null]) oldVal = nil;
   id newVal = [change objectForKey:NSKeyValueChangeNewKey];
   if (newVal == [NSNull null]) newVal = nil;
   //執(zhí)行該target下的所有block
   [_kvoBlockSet enumerateObjectsUsingBlock:^(void (^block)(__weak id obj, id oldVal, id newVal), BOOL * _Nonnull stop) {
       block(object, oldVal, newVal);
   }];
}

移除通知和觀察者

- (void)xw_removeNotificationForName:(NSString *)name{
   if (!name) return;
   NSMutableDictionary *allTargets = objc_getAssociatedObject(self, XWNotificationBlockKey);
   if (!allTargets.count) return;
   _XWBlockTarget *target = allTargets[name];
   if (!target) return;
   dispatch_semaphore_t notificationSemaphore = [self _xw_getSemaphoreWithKey:XWNotificationSemaphoreKey];
   dispatch_semaphore_wait(notificationSemaphore, DISPATCH_TIME_FOREVER);
   [[NSNotificationCenter defaultCenter] removeObserver:target];
   [allTargets removeObjectForKey:name];
   dispatch_semaphore_signal(notificationSemaphore);
   
}

- (void)xw_removeAllNotification{
   NSMutableDictionary *allTargets = objc_getAssociatedObject(self, XWNotificationBlockKey);
   if (!allTargets.count) return;
   dispatch_semaphore_t notificationSemaphore = [self _xw_getSemaphoreWithKey:XWNotificationSemaphoreKey];
   dispatch_semaphore_wait(notificationSemaphore, DISPATCH_TIME_FOREVER);
   [allTargets enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, _XWBlockTarget *target, BOOL * _Nonnull stop) {
       [[NSNotificationCenter defaultCenter] removeObserver:target];
   }];
   [allTargets removeAllObjects];
   dispatch_semaphore_signal(notificationSemaphore);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容