給通知和KVO添加block實(shí)現(xiàn)
給通知添加block的實(shí)現(xiàn)
- 創(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);
}