signalForSelector
跟系統(tǒng)的kvo實現(xiàn)原理類似。
3種方式
1, rac_signalForSelector:
原理:
1、創(chuàng)建子類, 對應(yīng)為isa的名字,加上后綴_RACSelectorSignal
( 類 : class返回類名, isa指向的類名, 需要注意這兩種情況的區(qū)別。
當(dāng)一個類注冊kvo觀察了, class返回的是原有類名, isa執(zhí)行了新的之類。這種情況就是兩種不同的返回。 )
2、重寫子類forwardInvocation方法。
當(dāng)調(diào)用子類的forwardInvocation選擇子時,調(diào)用新的newForwardInvocation block。 在新的newForwardInvocation block中調(diào)用RACForwardInvocation函數(shù),在全局RACForwardInvocation 中,invoke原有選擇子對應(yīng)的消息。 然后 給訂閱者發(fā)送消息。
如果沒有實現(xiàn)選擇子, doesNotRecognizeSelector。
如果子類沒有實現(xiàn)forwardInvocation,給父類發(fā)送 forwardInvocation, 如果實現(xiàn)了forwardInvocation ,則給這個子類發(fā)送forwardInvocation
3、重寫子類respondsToSelector方法。
4、重寫子類(通過class獲取的類名字)的class方法, 讓其返回原有的類名字。
5、重寫子類(通過isa獲取的類名字)的class方法,讓其返回原有的類名字。
6、重寫子類的methodSignatureForSelector方法。使其給給原有類發(fā)送methodSignatureForSelector消息。
7、將當(dāng)前recevier的類型設(shè)置為子類
8、重寫傳進來的selector的方法,讓其去調(diào)用forwardInvocation。
selector在receiver的類中實現(xiàn)了:
aliasSelector 綁定到原有方法。
重寫selector,讓其走forwardInvocation消息轉(zhuǎn)發(fā)。
先走原有方法--》 再發(fā)送信號。
selector在receiver的類中沒有實現(xiàn):
//如果實現(xiàn)了, 就能轉(zhuǎn)化參數(shù)。
//如果沒有實現(xiàn), 不能轉(zhuǎn)化,會產(chǎn)生異常崩潰。因為RACSignatureForUndefinedSelector統(tǒng)一當(dāng)作id類型的
@protocol MyAddProtocol<NSObject>
@optional
-(void)aa1:(NSString *) hello color:(UIColor *)color int:(NSInteger )intVlaue;
@end
#import "hookProxyDelegateViewController.h"
@interface hookProxyDelegateViewController () <UITableViewDelegate,UITableViewDataSource, MyAddProtocol>
-(void) test1 {
[[self rac_signalForSelector:@selector(aa1:color:int:)]subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"%@", x);
} ];
[self aa1:@"asdfa" color:[UIColor redColor] int:122];
}
//如果實現(xiàn)了, 就能轉(zhuǎn)化參數(shù)。
//如果沒有實現(xiàn), 不能轉(zhuǎn)化,會產(chǎn)生異常崩潰。因為RACSignatureForUndefinedSelector統(tǒng)一當(dāng)作id類型的
-(void)aa1:(NSString *)hello color:(UIColor *)color int:(NSInteger)intVlaue{
NSLog(@"asdfa");
}
2, rac_signalForSelector: fromProtocol:
selector在receiver的類中實現(xiàn)了:
跟rac_signalForSelector:方法效果相同。
selector在receiver的類中沒有實現(xiàn):
檢查在協(xié)議中selector方法是否聲明了, 現(xiàn)在必須協(xié)議方法列表中找,然后在不是可選協(xié)議方法列表中找。 都沒有找到。 報異常拋出。selector和協(xié)議不匹配。
重寫selector,讓其走forwardInvocation消息轉(zhuǎn)發(fā)。
3, [[RACDelegateProxy alloc] initWithProtocol:]
racdelegateProxy 模式改變身份
swizzle racdelegateProxy類的isa
swizzleDeallocIfNeed
不會swizzle isa
//看到這里,是用__block聲明的 originalDealloc是一個函數(shù)指針
__block void (*originalDealloc)(__unsafe_unretained id, SEL) = NULL;
id newDealloc = ^(__unsafe_unretained id self) {
//hook住的目的就是為了要攝入dispose
[compoundDisposable dispose];
block中捕獲了originalDealloc, originalDealloc指針本身的地址拷貝到堆上去了
執(zhí)行dealloc
msgSend(&superInfo, deallocSelector);
或者originalDealloc(self, deallocSelector);
}
可以看到 &originalDealloc的地址因為block的捕獲,地址變化了
if (!class_addMethod(classToSwizzle, deallocSelector, newDeallocIMP, "v@:"))
//the class already contains a method implementation with that name
//本類中實現(xiàn)了名字為dealloc的選擇子
調(diào)dealloc方法,會觸發(fā)到newDeallocIMP的方法指針調(diào)用
originalDealloc = (typeof(originalDealloc))method_setImplementation(deallocMethod, newDeallocIMP);
}
else {
// 增加成功了。本類沒有實現(xiàn)dealloc方法
當(dāng)執(zhí)行dealloc時,就會執(zhí)行newDealloc
}
//hook操作 Sets the implementation of a method.The previous implementation of the method.
//返回原來的函數(shù)指針, 保存原來的dealloc函數(shù)指針I(yè)MP到originalDealloc, 便于block里面調(diào)用
//調(diào)用Method時候,會調(diào)用newDeallocIMP指針,也就是新的deallocblock
originalDealloc = (typeof(originalDealloc))method_setImplementation(deallocMethod, newDeallocIMP);
所以,跟我們常見的swizzle不同的是,
方法交換,調(diào)A就是調(diào)B(B里面在調(diào)B,此時方法交換了,所以就能回調(diào)到原來的A),調(diào)B調(diào)就是A;
而上面的swillzeDealloc 不是交換。 只是一個調(diào)劑手段。 A調(diào)B(B里面調(diào)用A)