常用方法响应 -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) {
// 方法别名关联对象,存储subject,存在就直接返回,供外部订阅,不存在,去创建
RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);
if (subject != nil) return subject;
/**
创建名为 Class_RACSelectorSignal 的子类
重写子类一系统的方法,进行掩饰
使 isa 指针指向新创建的子类
返回新创建的 Class_RACSelectorSignal,下面的操作都针对 Class_RACSelectorSignal。
具体看 RACSwizzleClass()
*/
Class class = RACSwizzleClass(self);
NSCAssert(class != nil, @"Could not swizzle class of %@", self);
// 创建 subject,存到以方法别名为名的关联对象中。下次可直接取出使用。
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) {
// 监听的方法不存在
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:.
// 添加这个方法,实现为_objc_msgForward
if (!class_addMethod(class, selector, _objc_msgForward, typeEncoding)) {
// 如果添加失败,直接返一个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) {
// 方法存在,且方法的实现不是 _objc_msgForward
// Make a method alias for the existing method implementation.
const char *typeEncoding = method_getTypeEncoding(targetMethod);
RACCheckTypeEncoding(typeEncoding);
/**
添加一个方法,方法名是 rac_alias_originMethod,实现是目标方法 originMethod的实现。
然后重写目标方法的实现,改为_objc_msgForward。
相当于,下次,再调用目标方法的时候,会直接走消息转发流程,然后RAC在消息转发流程中,先触发 signal 响应,然后再执行 rac_alias_originMethod,也就是原方法的实现。以达到监听方法的目的。
*/
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) {
/**
因为 class方法被重写,所以这两个值有可能被替换
statedClass:Class,对外表示的类
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.
// 这里是兼容系统KVO,因为系统KVO也会修改 isa。如果已经使用过系统KVO,则直接交换相关方法,不需要再重新新类。
@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 指针,创建名为 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: 方法实现
rac_alias_selector 方法存在时,执行方法,subject sendNext:
当方法未找到时,subject sendError:
*/
RACSwizzleForwardInvocation(subclass);
// 修改 Class_RACSelectorSignal -respondsToSelector: 方法实现,获取参数 selector 方法,当方法存在,并且方法实现不是 _objc_msg
/**
修改 Class_RACSelectorSignal -respondsToSelector: 方法实现
获取参数 selector方法,当方法存在,且方法实现不是 _objc_msgForward
获取 Rac_alias_selector 对应的关联对象,不为空是,返回YES。
如果方法不存在,或方法实现是 _objc_msgForward 时
返回原方法实现。
*/
RACSwizzleRespondsToSelector(subclass);
// 修改 Class_RACSelectorSignal 的 -class 方法实现,返回 Class
RACSwizzleGetClass(subclass, statedClass);
// 修改 Class_RACSelectorSignal 的 +class 方法实现,返回 Class
RACSwizzleGetClass(object_getClass(subclass), statedClass);
// 重写 -methodSignatureForSelectorMethod: 实现,当方法存在时,返回方法签名,方法不存在时,调用 super -methodSignatureForSelectorMethod: 方法,也就是 Class 的方法。
RACSwizzleMethodSignatureForSelector(subclass);
// 注册子类
objc_registerClassPair(subclass);
}
// 修改 isa 指针
object_setClass(self, subclass);
objc_setAssociatedObject(self, RACSubclassAssociationKey, subclass, OBJC_ASSOCIATION_ASSIGN);
return subclass;
}
// 修改-forwardInvocation: 实现
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 是否能响应
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];
// 别名方法的实现,是原方法的实现,因为有可能监听一个未实现的方法,所以别名方法有可能无法响应。所以这里判断一下。
if (respondsToAlias) {
invocation.selector = aliasSelector;
[invocation invoke];
}
if (subject == nil) return respondsToAlias;
[subject sendNext:invocation.rac_argumentsTuple];
return YES;
}
// 修改-respondsToSelector: 方法实现
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 监听方法前后,类结构图