其實這個源碼大部分的內(nèi)容都是runtime的座硕,如果不了解runtime,這個看起來會比較蛋疼初肉,源碼很多呻惕,分成一小部分一小部分慢慢看荆责。
先看這個方法RACSwizzleForwardInvocation
//這個方法就是swizzle一個class的forwardInvocation函數(shù),熟悉oc方法消息轉(zhuǎn)發(fā)的同學(xué)都知道亚脆,當(dāng)一個對象收到一個不能響應(yīng)的消息做院,最后一步都會走到這個方法。
static void RACSwizzleForwardInvocation(Class class) {
SEL forwardInvocationSEL = @selector(forwardInvocation:);
Method forwardInvocationMethod = class_getInstanceMethod(class, forwardInvocationSEL);
//如果forwardInvocation已經(jīng)有實現(xiàn)了濒持,就存下键耕。。
void (*originalForwardInvocation)(id, SEL, NSInvocation *) = NULL;
if (forwardInvocationMethod != NULL) {
originalForwardInvocation = (__typeof__(originalForwardInvocation))method_getImplementation(forwardInvocationMethod);
}
//去定義新的forwardInvocation實現(xiàn)
id newForwardInvocation = ^(id self, NSInvocation *invocation) {
//如果已經(jīng)被rac_signalForSelector過了柑营,直接走一遍RACForwardInvocation屈雄,然后返回
BOOL matched = RACForwardInvocation(self, invocation);
if (matched) return;
//如果沒有的話就直接走遠(yuǎn)來的實現(xiàn)
if (originalForwardInvocation == NULL) {
[self doesNotRecognizeSelector:invocation.selector];
} else {
originalForwardInvocation(self, forwardInvocationSEL, invocation);
}
};
class_replaceMethod(class, forwardInvocationSEL, imp_implementationWithBlock(newForwardInvocation), "v@:@");
}
關(guān)于上段的RACForwardInvocation,源碼如下
static BOOL RACForwardInvocation(id self, NSInvocation *invocation) {
//獲取帶rac_alias_前綴的方法
SEL aliasSelector = RACAliasForSelector(invocation.selector);
//可以看到sel其實也就是個const void *key
RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);
Class class = object_getClass(invocation.target);
BOOL respondsToAlias = [class instancesRespondToSelector:aliasSelector];
//如果這個class有帶rac_alias_前綴的方法由境,就執(zhí)行
if (respondsToAlias) {
invocation.selector = aliasSelector;
[invocation invoke];
}
if (subject == nil) return respondsToAlias;
//給訂閱這發(fā)送invovation的入?yún)? [subject sendNext:invocation.rac_argumentsTuple];
return YES;
}
下面在繼續(xù)看RACSwizzleRespondsToSelector棚亩,其實這個方法就是去swizzle一個class的respondsToSelector的方法
static void RACSwizzleRespondsToSelector(Class class) {
SEL respondsToSelectorSEL = @selector(respondsToSelector:);
Method respondsToSelectorMethod = class_getInstanceMethod(class, respondsToSelectorSEL);
BOOL (*originalRespondsToSelector)(id, SEL, SEL) = (__typeof__(originalRespondsToSelector))method_getImplementation(respondsToSelectorMethod);
//和上面一個套路。虏杰。
id newRespondsToSelector = ^ BOOL (id self, SEL selector) {
//這個方法就是去根據(jù)selector去找一個class的method讥蟆,其實系統(tǒng)有個方法
class_getInstanceMethod,不懂為啥要自己寫纺阔。瘸彤。
Method method = rac_getImmediateInstanceMethod(class, selector);
if (method != NULL && method_getImplementation(method) == _objc_msgForward) {
//如果有alias的selector則返回yes,否則就返回原來的respondsToSelector的實現(xiàn)結(jié)果笛钝。
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));
}
下面繼續(xù)看RACSwizzleGetClass质况,這個就是去swizzle一個[self class] 這個get方法。
static void RACSwizzleGetClass(Class class, Class statedClass) {
SEL selector = @selector(class);
Method method = class_getInstanceMethod(class, selector);
IMP newIMP = imp_implementationWithBlock(^(id self) {
//返回statedClass
return statedClass;
});
class_replaceMethod(class, selector, newIMP, method_getTypeEncoding(method));
}
熟悉runtime的都知道重寫forwardInvocation玻靡,一定要重寫方法簽名结榄,也就是methodSignatureForSelector這個函數(shù)。下面就開始看這個方法囤捻。
static void RACSwizzleMethodSignatureForSelector(Class class) {
IMP newIMP = imp_implementationWithBlock(^(id self, SEL selector) {
//這時候你去調(diào)self.class并不會拿到真實的臼朗,因為被我們swizzle掉了
Class actualClass = object_getClass(self);
Method method = class_getInstanceMethod(actualClass, selector);
//如果有這個方法,那直接返回簽名蝎土,如果沒有的話视哑,那就調(diào)super
if (method == NULL) {
struct objc_super target = {
.super_class = class_getSuperclass(class),
.receiver = self,
};
NSMethodSignature * (*messageSend)(struct objc_super *, SEL, SEL) = (__typeof__(messageSend))objc_msgSendSuper;
//這個相當(dāng)于用[super ]
return messageSend(&target, @selector(methodSignatureForSelector:), selector);
}
char const *encoding = method_getTypeEncoding(method);
return [NSMethodSignature signatureWithObjCTypes:encoding];
});
SEL selector = @selector(methodSignatureForSelector:);
Method methodSignatureForSelectorMethod = class_getInstanceMethod(class, selector);
class_replaceMethod(class, selector, newIMP, method_getTypeEncoding(methodSignatureForSelectorMethod));
}
以上是基礎(chǔ)部分現(xiàn)在可以開始看signalforselector這個方法了,其核心邏輯在下面這個方法中
static RACSignal *NSObjectRACSignalForSelector(NSObject *self, SEL selector, Protocol *protocol) {
//獲取帶rac_alias_頭的方法誊涯,正常第一次都是沒有的
SEL aliasSelector = RACAliasForSelector(selector);
@synchronized (self) {
//如果已經(jīng)被rac_signalForSelector過了挡毅,那已經(jīng)有這個subject了,直接返回就行了
RACSubject *subject = objc_getAssociatedObject(self, aliasSelector);
if (subject != nil) return subject;
//這個方法上面已經(jīng)說了暴构,就是swizzzle這個class一些列協(xié)議轉(zhuǎn)發(fā)的方法跪呈。
Class class = RACSwizzleClass(self);
NSCAssert(class != nil, @"Could not swizzle class of %@", self);
//第一次去set下這個subject
subject = [[RACSubject subject] setNameWithFormat:@"%@ -rac_signalForSelector: %s", self.rac_description, 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) {
//如果沒有的話段磨,不會crash,會走下面的邏輯庆械,首先去定義入?yún)⒌念愋娃崩#琧lassaddmethod的時候會用到。
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);
// 去添加這個方法缭乘,如果不成功沐序,能直接返回racsignal error
if (!class_addMethod(class, selector, _objc_msgForward, typeEncoding)) {
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) {
//如果這個方法存在
// Make a method alias for the existing method implementation.
const char *typeEncoding = method_getTypeEncoding(targetMethod);
RACCheckTypeEncoding(typeEncoding);
添加一個帶標(biāo)志為的方法。
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);
//siwzzle這個selector的實現(xiàn)堕绩,讓他繼續(xù)把消息發(fā)送出去這樣就能走到我們上面的forwardInvocation策幼,那個地方我們做了自己的邏輯,_objc_msgForward就是發(fā)送消息奴紧。特姐。
// Redefine the selector to call -forwardInvocation:.
class_replaceMethod(class, selector, _objc_msgForward, method_getTypeEncoding(targetMethod));
}
return subject;
}
}