1

UITableView/UICollectionViewデリゲートがプロキシ オブジェクト ( ではなくNSProxy、通常のオブジェクト)によって転送されているケースに遭遇しました。

特定のデリゲート メソッドに応じて、プロキシはそれを実際にメソッドに応答する 2 つのオブジェクトのいずれかに転送します。

デリゲート コールバックが与えられた場合、メソッド呼び出しに応答している「真の」インスタンスを知りたいです。

プロキシ コードは次のようになります。

@implementation DelegateSplitter

- (instancetype)initWithFirstDelegate:(id<NSObject>)firstDelegate secondDelegate:(id<NSObject>)secondDelegate
{
    if(self = [super init])
    {
        _firstDelegate = firstDelegate;
        _secondDelegate = secondDelegate;
    }

    return self;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    SEL aSelector = [anInvocation selector];

    if([self.firstDelegate respondsToSelector:aSelector])
    {
        [anInvocation invokeWithTarget:self.firstDelegate];
    }

    if([self.secondDelegate respondsToSelector:aSelector])
    {
        [anInvocation invokeWithTarget:self.secondDelegate];
    }
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature *first = [(NSObject *)self.firstDelegate methodSignatureForSelector:aSelector];
    NSMethodSignature *second = [(NSObject *)self.secondDelegate methodSignatureForSelector:aSelector];

    if(first)
    {
        return first;
    }
    else if(second)
    {
        return second;
    }

    return nil;
}

- (BOOL)respondsToSelector:(SEL)aSelector
{
    if([self.firstDelegate respondsToSelector:aSelector] || [self.secondDelegate respondsToSelector:aSelector])
    {
        return YES;
    }
    else
    {
        return NO;
    }
}

@end

私のコードは次のようになります:

デリゲート メソッドが与えられた場合、どのインスタンスが応答しているかを知りたい:

    // delegate is an instance of DelegateSplitter
    id <UITableViewDelegate> delegate = tv.delegate; 

    SEL didSelectItemSelector = @selector(collectionView:didSelectItemAtIndexPath:);

    if ([delegate respondsToSelector:didSelectItemSelector]) {
       // the delegate splitter doesn't forward the call
       ...
       return;
    }

// the delegate (proxy) forwards the method to a different instance
    if (![delegate.class instancesRespondToSelector:didSelectItemSelector]) {
            // the delegate responds to selector but the class instances themselves do not respond to the selector. This is possible if the delegate is forwarding all invocations to a different object

               NSObject *d = (NSObject *)delegate;
         NSMethodSignature *ms = [d methodSignatureForSelector:didSelectItemSelector];

         if (ms) {

          ** I WANT TO GET THE INSTANCE WHICH IS RESPONDING**
          ????
          HOW DO I GET IT
          ?????
         }
    }

編集:

現在のハック (より全体的なものが欲しい):

モック オブジェクトでフォワーダーを呼び出し、ターゲット オブジェクトを取得する

@implementation NSObject (HACK)
- (id)responderToSelector:(SEL)selector
{
  if ([self respondsToSelector:selector] && [self.class instancesRespondToSelector:selector]) {
    return self; // the class and the instance actually will respond to the selector when called
  }

  if ([self respondsToSelector:selector]) {
    // invocations are forwarded
    id forward = [self forwardingTargetForSelector:selector];
    if (forward && forward != self) {
      return [forward responderToSelector:selector];
    }

      NSMethodSignature *ms = [self methodSignatureForSelector:selector];
      if (ms) {

        MockInvocation *mockInvocation = [MockInvocation invocationWithMethodSignature:ms];
        mockInvocation.selector = selector;
        [self forwardInvocation:mockInvocation];
        return mockInvocation.target ?: mockInvocation.innerTarget;
      }

  }
  return nil;
}


@interface MockInvocation : NSInvocation

@property (nonatomic, weak) id innerTarget;
@end

@implementation IIOMockInvocation

- (void)invoke
{
}
- (void)invokeWithTarget:(id)target
{
  _innerTarget = target;
}

@end
4

0 に答える 0