in ComponentKit/Core/Action/CKAction.mm [176:220]
CKActionInfo CKActionFind(SEL selector, id target) noexcept
{
// If we don't have a selector or target, we bail early.
if (!selector || !target) {
return {};
}
id responder = ([target respondsToSelector:@selector(targetForAction:withSender:)]
? [target targetForAction:selector withSender:target]
: target);
RCCAssert(![responder isProxy],
@"NSProxy can't be a responder for target-selector CKAction. Please use a block action instead.");
IMP imp = [responder methodForSelector:selector];
while (!imp) {
// From https://www.mikeash.com/pyblog/friday-qa-2009-03-27-objective-c-message-forwarding.html
// 1. Lazy method resolution
if ( [[responder class] resolveInstanceMethod:selector]) {
imp = [responder methodForSelector:selector];
// The responder resolved its instance method, we now have a valid responder/signature
break;
}
// 2. Fast-forwarding path
id forwardingTarget = [responder forwardingTargetForSelector:selector];
if (!forwardingTarget || forwardingTarget == responder) {
// Bail, the object they're asking us to message will just crash if the method is invoked on them
RCCFailAssertWithCategory(NSStringFromSelector(selector),
@"Forwarding target failed for action: %@ %@",
NSStringFromSelector(selector),
target);
return {};
}
responder = forwardingTarget;
RCCAssert(![responder isProxy],
@"NSProxy can't be a responder for target-selector CKAction. Please use a block action instead.");
imp = [responder methodForSelector:selector];
}
RCCAssert(imp != nil,
@"IMP not found for selector => SEL: %@ | target: %@",
NSStringFromSelector(selector), [target class]);
return {imp, responder};
}