Rachook伎倆

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)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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