CKActionInfo CKActionFind()

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};
}