1. Preface
In development, when the custom view is complex and there are many events to be handled
You need to use delegate or block to pass events back and forth
When there are more levels, nesting also increases
The result is a delegate nested delegate or a block nested block
Upload layer by layer
I'm tired, I'm upset
When you need to modify or maintain it later
Jump here, jump there, jump for half a day to find a place
2. Main topic - UIResponder
Let's start with a diagram: UIResponder and its subclasses
UIResponder has a property: nextResponder, next responder
Use this to send events back and forth
New category:
/// UIResponder+JHRouter.h
@interface UIResponder (JHRouter)
- (void)jh_routerWithSelector:(NSString *)selector
sender:(id)sender
info:(NSDictionary *)info;
@end
/// UIResponder+JHRouter.m
#import "UIResponder+JHRouter.h"
@implementation UIResponder (JHRouter)
/*
if an object respondsToSelector: selector
[object respondsToSelector:NSSelectorFromString(selector)]
you should do something.
invoke [super jh_routerWithSelector:selector sender:sender info:info];
Let the events continue to pass up
*/
- (void)jh_routerWithSelector:(NSString *)selector
sender:(id)sender
info:(NSDictionary *)info
{
[[self nextResponder] jh_routerWithSelector:selector
sender:sender
info:info];
}
@end
When selector is used as SEL
You can add a classification to NSObject
Then directly
if ([self respondsToSelector:NSSelectorFromString(selector)]){
[self performSelector:NSSelectorFromString(selector) withObjects:info];
}
/ / classification:
@interface NSObject (PerformSelector)
- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects;
@end
#import "NSObject+PerformSelector.h"
@implementation NSObject (PerformSelector)
- (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects
{
//
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
//
if (!signature) {
NSString *reason = [NSString stringWithFormat:@"oops~ unrecognized selector %@ sent to instance %@ : %lx",NSStringFromSelector(aSelector),[self class],(unsigned long)[self hash]];
@throw [[NSException alloc] initWithName:@"com.haocold" reason:reason userInfo:nil];
return nil;
}
//
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = aSelector;
// parameters
// first: _cmd
// second: target
NSInteger arguments = signature.numberOfArguments - 2;
//
NSInteger count = MIN(arguments, objects.count);
for (int i = 0; i < count; ++i) {
id obj = objects[i];
if ([obj isKindOfClass:[NSNull class]]) {
obj = nil;
}
[invocation setArgument:&obj atIndex:i+2];
}
//
[invocation invoke];
//
id result = nil;
if (signature.methodReturnLength != 0) {
[invocation getReturnValue:&result];
}
return result;
}
@end
selector can also be used as a flag, identifier
if ([selector isEqualToString:@"xxx"]) {
// do something with info.
}
sender indicates the view of the trigger event. If you don't pay attention to this, you can send nil
info indicates the parameters to be passed. After each responder, some new parameters can be added
view1 added view2, view2 added view3
Within view3
[self.nextResponder jh_routerWithSelector:@"view3" sender:nil info:nil];
Within view2
- (void)jh_routerWithSelector:(NSString *)selector sender:(id)sender info:(NSDictionary *)info
{
// Add some new parameters to info
NSMutableDictionary *newInfo = [[NSMutableDictionary alloc] initWithDictionary:info];
[newInfo setObject:@"name" forKey:@"xx"];
[self.nextResponder jh_routerWithSelector:selector sender:sender info:newInfo];
}
Within view1
- (void)jh_routerWithSelector:(NSString *)selector sender:(id)sender info:(NSDictionary *)info{
NSLog(@"info:%@",info);
//info:{
// xx = name;
//}
}
3. pay attention to
When adding a view to the window with a view, the echo event will be interrupted!!!