常用方法響應(yīng) -rac_signalForSelector:
使用:
[[[self rac_signalForSelector:@selector(viewWillAppear:)] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(RACTuple * _Nullable x) {
}];
源碼
- NSObject+RACSelectorSignal
- (RACSignal *)rac_signalForSelector:(SEL)selector {
NSCParameterAssert(selector != NULL);
return NSObjectRACSignalForSelector(self, selector, NULL);
}
static RACSignal *NSObjectRACSignalForSelector(NSObject *self, SEL selector, Protocol *protocol) {
// rac_alias_ + 方法名 = 方法別名
SEL aliasSelector = RACAliasForSelector(selector);
@synchronized (self) {
// 方法別名關(guān)聯(lián)對(duì)象于置,存儲(chǔ)subject褥芒,存在就直接返回,供外部訂閱做入,不存在,去創(chuàng)建
RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);
if (subject != nil) return subject;
/**
創(chuàng)建名為 Class_RACSelectorSignal 的子類
重寫子類一系統(tǒng)的方法同衣,進(jìn)行掩飾
使 isa 指針指向新創(chuàng)建的子類
返回新創(chuàng)建的 Class_RACSelectorSignal竟块,下面的操作都針對(duì) Class_RACSelectorSignal。
具體看 RACSwizzleClass()
*/
Class class = RACSwizzleClass(self);
NSCAssert(class != nil, @"Could not swizzle class of %@", self);
// 創(chuàng)建 subject耐齐,存到以方法別名為名的關(guān)聯(lián)對(duì)象中浪秘。下次可直接取出使用蒋情。
subject = [[RACSubject subject] setNameWithFormat:@"%@ -rac_signalForSelector: %s", RACDescription(self), sel_getName(selector)];
objc_setAssociatedObject(self, aliasSelector, subject, OBJC_ASSOCIATION_RETAIN);
[self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
[subject sendCompleted];
}]];
Method targetMethod = class_getInstanceMethod(class, selector);
if (targetMethod == NULL) {
// 監(jiān)聽的方法不存在
const char *typeEncoding;
if (protocol == NULL) {
typeEncoding = RACSignatureForUndefinedSelector(selector);
} else {
// Look for the selector as an optional instance method.
struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, NO, YES);
if (methodDescription.name == NULL) {
// Then fall back to looking for a required instance
// method.
methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES);
NSCAssert(methodDescription.name != NULL, @"Selector %@ does not exist in <%s>", NSStringFromSelector(selector), protocol_getName(protocol));
}
typeEncoding = methodDescription.types;
}
RACCheckTypeEncoding(typeEncoding);
// Define the selector to call -forwardInvocation:.
// 添加這個(gè)方法,實(shí)現(xiàn)為_objc_msgForward
if (!class_addMethod(class, selector, _objc_msgForward, typeEncoding)) {
// 如果添加失敗耸携,直接返一個(gè)ErrorSignal棵癣。
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedString(@"A race condition occurred implementing %@ on class %@", nil), NSStringFromSelector(selector), class],
NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Invoke -rac_signalForSelector: again to override the implementation.", nil)
};
return [RACSignal error:[NSError errorWithDomain:RACSelectorSignalErrorDomain code:RACSelectorSignalErrorMethodSwizzlingRace userInfo:userInfo]];
}
} else if (method_getImplementation(targetMethod) != _objc_msgForward) {
// 方法存在,且方法的實(shí)現(xiàn)不是 _objc_msgForward
// Make a method alias for the existing method implementation.
const char *typeEncoding = method_getTypeEncoding(targetMethod);
RACCheckTypeEncoding(typeEncoding);
/**
添加一個(gè)方法夺衍,方法名是 rac_alias_originMethod狈谊,實(shí)現(xiàn)是目標(biāo)方法 originMethod的實(shí)現(xiàn)。
然后重寫目標(biāo)方法的實(shí)現(xiàn)沟沙,改為_objc_msgForward河劝。
相當(dāng)于,下次矛紫,再調(diào)用目標(biāo)方法的時(shí)候赎瞎,會(huì)直接走消息轉(zhuǎn)發(fā)流程,然后RAC在消息轉(zhuǎn)發(fā)流程中颊咬,先觸發(fā) signal 響應(yīng)务甥,然后再執(zhí)行 rac_alias_originMethod,也就是原方法的實(shí)現(xiàn)喳篇。以達(dá)到監(jiān)聽方法的目的敞临。
*/
BOOL addedAlias __attribute__((unused)) = class_addMethod(class, aliasSelector, method_getImplementation(targetMethod), typeEncoding);
NSCAssert(addedAlias, @"Original implementation for %@ is already copied to %@ on %@", NSStringFromSelector(selector), NSStringFromSelector(aliasSelector), class);
// Redefine the selector to call -forwardInvocation:.
class_replaceMethod(class, selector, _objc_msgForward, method_getTypeEncoding(targetMethod));
}
return subject;
}
}
// 修改 Class
static Class RACSwizzleClass(NSObject *self) {
/**
因?yàn)?class方法被重寫,所以這兩個(gè)值有可能被替換
statedClass:Class杭隙,對(duì)外表示的類
baseClass:真正的類哟绊,isa 指向的類 Class 或 Class_RACSelectorSignal
*/
Class statedClass = self.class;
Class baseClass = object_getClass(self);
// The "known dynamic subclass" is the subclass generated by RAC.
// It's stored as an associated object on every instance that's already
// been swizzled, so that even if something else swizzles the class of
// this instance, we can still access the RAC generated subclass.
Class knownDynamicSubclass = objc_getAssociatedObject(self, RACSubclassAssociationKey);
if (knownDynamicSubclass != Nil) return knownDynamicSubclass;
NSString *className = NSStringFromClass(baseClass);
if (statedClass != baseClass) {
// If the class is already lying about what it is, it's probably a KVO
// dynamic subclass or something else that we shouldn't subclass
// ourselves.
//
// Just swizzle -forwardInvocation: in-place. Since the object's class
// was almost certainly dynamically changed, we shouldn't see another of
// these classes in the hierarchy.
//
// Additionally, swizzle -respondsToSelector: because the default
// implementation may be ignorant of methods added to this class.
// 這里是兼容系統(tǒng)KVO,因?yàn)橄到y(tǒng)KVO也會(huì)修改 isa痰憎。如果已經(jīng)使用過系統(tǒng)KVO票髓,則直接交換相關(guān)方法,不需要再重新新類铣耘。
@synchronized (swizzledClasses()) {
if (![swizzledClasses() containsObject:className]) {
// 未交換方法
RACSwizzleForwardInvocation(baseClass);
RACSwizzleRespondsToSelector(baseClass);
RACSwizzleGetClass(baseClass, statedClass);
RACSwizzleGetClass(object_getClass(baseClass), statedClass);
RACSwizzleMethodSignatureForSelector(baseClass);
[swizzledClasses() addObject:className];
}
}
return baseClass;
}
// 未修改 isa 指針洽沟,創(chuàng)建名為 Class_RACSelectorSignal 的子類
const char *subclassName = [className stringByAppendingString:RACSubclassSuffix].UTF8String;
Class subclass = objc_getClass(subclassName);
if (subclass == nil) {
subclass = objc_allocateClassPair(baseClass, subclassName, 0);
if (subclass == nil) return nil;
/**
修改 Class_RACSelectorSignal -forwardInvocation: 方法實(shí)現(xiàn)
rac_alias_selector 方法存在時(shí),執(zhí)行方法蜗细,subject sendNext:
當(dāng)方法未找到時(shí)裆操,subject sendError:
*/
RACSwizzleForwardInvocation(subclass);
// 修改 Class_RACSelectorSignal -respondsToSelector: 方法實(shí)現(xiàn),獲取參數(shù) selector 方法炉媒,當(dāng)方法存在踪区,并且方法實(shí)現(xiàn)不是 _objc_msg
/**
修改 Class_RACSelectorSignal -respondsToSelector: 方法實(shí)現(xiàn)
獲取參數(shù) selector方法,當(dāng)方法存在吊骤,且方法實(shí)現(xiàn)不是 _objc_msgForward
獲取 Rac_alias_selector 對(duì)應(yīng)的關(guān)聯(lián)對(duì)象缎岗,不為空是,返回YES白粉。
如果方法不存在传泊,或方法實(shí)現(xiàn)是 _objc_msgForward 時(shí)
返回原方法實(shí)現(xiàn)鼠渺。
*/
RACSwizzleRespondsToSelector(subclass);
// 修改 Class_RACSelectorSignal 的 -class 方法實(shí)現(xiàn),返回 Class
RACSwizzleGetClass(subclass, statedClass);
// 修改 Class_RACSelectorSignal 的 +class 方法實(shí)現(xiàn)眷细,返回 Class
RACSwizzleGetClass(object_getClass(subclass), statedClass);
// 重寫 -methodSignatureForSelectorMethod: 實(shí)現(xiàn)拦盹,當(dāng)方法存在時(shí),返回方法簽名溪椎,方法不存在時(shí)普舆,調(diào)用 super -methodSignatureForSelectorMethod: 方法,也就是 Class 的方法校读。
RACSwizzleMethodSignatureForSelector(subclass);
// 注冊(cè)子類
objc_registerClassPair(subclass);
}
// 修改 isa 指針
object_setClass(self, subclass);
objc_setAssociatedObject(self, RACSubclassAssociationKey, subclass, OBJC_ASSOCIATION_ASSIGN);
return subclass;
}
// 修改-forwardInvocation: 實(shí)現(xiàn)
static void RACSwizzleForwardInvocation(Class class) {
SEL forwardInvocationSEL = @selector(forwardInvocation:);
Method forwardInvocationMethod = class_getInstanceMethod(class, forwardInvocationSEL);
// Preserve any existing implementation of -forwardInvocation:.
void (*originalForwardInvocation)(id, SEL, NSInvocation *) = NULL;
if (forwardInvocationMethod != NULL) {
originalForwardInvocation = (__typeof__(originalForwardInvocation))method_getImplementation(forwardInvocationMethod);
}
// Set up a new version of -forwardInvocation:.
//
// If the selector has been passed to -rac_signalForSelector:, invoke
// the aliased method, and forward the arguments to any attached signals.
//
// If the selector has not been passed to -rac_signalForSelector:,
// invoke any existing implementation of -forwardInvocation:. If there
// was no existing implementation, throw an unrecognized selector
// exception.
id newForwardInvocation = ^(id self, NSInvocation *invocation) {
BOOL matched = RACForwardInvocation(self, invocation);
if (matched) return;
if (originalForwardInvocation == NULL) {
[self doesNotRecognizeSelector:invocation.selector];
} else {
originalForwardInvocation(self, forwardInvocationSEL, invocation);
}
};
class_replaceMethod(class, forwardInvocationSEL, imp_implementationWithBlock(newForwardInvocation), "v@:@");
}
// rac_alias_selector 是否能響應(yīng)
static BOOL RACForwardInvocation(id self, NSInvocation *invocation) {
SEL aliasSelector = RACAliasForSelector(invocation.selector);
RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);
Class class = object_getClass(invocation.target);
BOOL respondsToAlias = [class instancesRespondToSelector:aliasSelector];
// 別名方法的實(shí)現(xiàn)奔害,是原方法的實(shí)現(xiàn),因?yàn)橛锌赡鼙O(jiān)聽一個(gè)未實(shí)現(xiàn)的方法地熄,所以別名方法有可能無法響應(yīng)。所以這里判斷一下芯杀。
if (respondsToAlias) {
invocation.selector = aliasSelector;
[invocation invoke];
}
if (subject == nil) return respondsToAlias;
[subject sendNext:invocation.rac_argumentsTuple];
return YES;
}
// 修改-respondsToSelector: 方法實(shí)現(xiàn)
static void RACSwizzleRespondsToSelector(Class class) {
SEL respondsToSelectorSEL = @selector(respondsToSelector:);
// Preserve existing implementation of -respondsToSelector:.
Method respondsToSelectorMethod = class_getInstanceMethod(class, respondsToSelectorSEL);
BOOL (*originalRespondsToSelector)(id, SEL, SEL) = (__typeof__(originalRespondsToSelector))method_getImplementation(respondsToSelectorMethod);
// Set up a new version of -respondsToSelector: that returns YES for methods
// added by -rac_signalForSelector:.
//
// If the selector has a method defined on the receiver's actual class, and
// if that method's implementation is _objc_msgForward, then returns whether
// the instance has a signal for the selector.
// Otherwise, call the original -respondsToSelector:.
id newRespondsToSelector = ^ BOOL (id self, SEL selector) {
Method method = rac_getImmediateInstanceMethod(class, selector);
if (method != NULL && method_getImplementation(method) == _objc_msgForward) {
SEL aliasSelector = RACAliasForSelector(selector);
if (objc_getAssociatedObject(self, aliasSelector) != nil) return YES;
}
return originalRespondsToSelector(self, respondsToSelectorSEL, selector);
};
class_replaceMethod(class, respondsToSelectorSEL, imp_implementationWithBlock(newRespondsToSelector), method_getTypeEncoding(respondsToSelectorMethod));
}
RAC 監(jiān)聽方法前后端考,類結(jié)構(gòu)圖