origin

The iOS object transfer modes include: direct property, Delegate, KVO, Block, Protocol, polymorphism, and target-Action. But one day WHEN I was looking through the technical documentation, I came across a whole new way of interacting with objects based on ResponsderChain.

This allows events and parameters to be passed down the responder chain by hanging a category on the UIResponder. It’s like borrowing from the UIResponder chain to implement your own event passing, which is especially useful when events need to be passed through layers, but this object interaction is only useful for UIResponder objects on the responder chain.

implementation

Only one CateGroy is required to implement responderchain-based object interaction

.h files

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIResponder (Router)

- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo;

@end

NS_ASSUME_NONNULL_END

Copy the code

.m files

#import "UIResponder+Router.h"@implementation UIResponder (Router) - (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo  { [[self nextResponder] routerEventWithName:eventName userInfo:userInfo]; } @endCopy the code

When sending events:

[self routerEventWithName:@"evevta" userInfo:@{@"key": @"a"}];
Copy the code

When responding to an event:

- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo { You call the following statement / / [super routerEventWithName: eventName the userInfo: the userInfo]; }Copy the code

In the above code, if the event comes from more than one source, you cannot avoid the need for if-else statements to handle specific events accordingly. This can cause a lot of if-else, so consider NSInvocation to eliminate if-else:

- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo { You call the following statement / / [super routerEventWithName: eventName the userInfo: the userInfo]; NSInvocation *invocation = self.eventStrategy[eventName]; [invocationsetArgument:&userInfo atIndex:2];
    [invocation invoke];
    
}
Copy the code

Self. eventStrategy is a dictionary in the event accepted class. The dictionary has the eventName as the Key and the processing logic encapsulated in the NSInvocation value

(NSDictionary <NSString *, NSInvocation *> *)eventStrategy {// The invocation can be set to a global variable to prevent errors and the code will be clearerif (_eventStrategy == nil) {
        _eventStrategy = @{
            @"evevta":[self createInvocationWithSelector:@selector(responderChainA:)],
            @"evevtb":[self createInvocationWithSelector:@selector(responderChainB:)],
            @"evevtc":[self createInvocationWithSelector:@selector(responderChainC:)]
        };
    }
    return _eventStrategy;
}

Copy the code

In this way, you can avoid the lengthy if-else. Download the demo for details.

Analysis of the

The downside of this object interaction is obvious: it only works with UIResopnder objects that exist on the Responder Chain.

The advantages are also quite many:

  • The Responder Chain can be used instead of a delegate layer. In pages with complex UI levels, this approach avoids unnecessary delegate declarations.
  • Since many custom events are passed in this way, the logic of event processing is brought together. A breakpoint in this method can manage all events.
  • The UIViewController/UIView event logic is managed well with the Strategy Invocation and is not scattered all over the place.

As shown in the demo