利用OC对象的消息重定向forwardingTargetForSelector方法构建高扩展性的滤镜功能
在OC中,当像一个对象发送消息,而对象找到消息后,从它的类方法列表,父类方法列表,一直找到根类方法列表都没有找到与这个选择子对应的函数指针。那么这个对象就会触发消息转发机制。
OC对象的继承链和isa指针链如图:
整个调用流程图如下:
整个代码调用顺序如下:
//1 + (BOOL)resolveClassMethod:(SEL)sel { NSLog(@"1---%@",NSStringFromSelector(sel)); NSLog(@"1---%@",NSStringFromSelector(_cmd)); return NO; } + (BOOL)resolveInstanceMethod:(SEL)sel { NSLog(@"1---%@",NSStringFromSelector(sel)); NSLog(@"1---%@",NSStringFromSelector(_cmd)); return NO; } //2 - (id)forwardingTargetForSelector:(SEL)aSelector { NSLog(@"2---%@",NSStringFromSelector(aSelector)); NSLog(@"2---%@",NSStringFromSelector(_cmd)); return nil; } //3.最后一步,返回方法签名 -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{ NSLog(@"3---%@",NSStringFromSelector(aSelector)); NSLog(@"3---%@",NSStringFromSelector(_cmd)); if ([NSStringFromSelector(aSelector) isEqualToString:@"gogogo"]) { return [[UnknownModel2 new] methodSignatureForSelector:aSelector]; } return [super methodSignatureForSelector:aSelector]; } //3.1处理返回的方法签名 -(void)forwardInvocation:(NSInvocation *)anInvocation{ NSLog(@"4---%@",NSStringFromSelector(_cmd)); NSLog(@"4-最后一步--%@",anInvocation); if ([NSStringFromSelector(anInvocation.selector) isEqualToString:@"gogogo"]) { [anInvocation invokeWithTarget:[UnknownModel2 new]]; }else{ [super forwardInvocation:anInvocation]; } } //触发崩溃 - (void)doesNotRecognizeSelector:(SEL)aSelector { }
打印结果如下:
2018-12-27 00:14:00.469445+0800 iOS_KnowledgeStructure[7940:110114] 1---gogogo 2018-12-27 00:14:00.469613+0800 iOS_KnowledgeStructure[7940:110114] 1---resolveInstanceMethod: 2018-12-27 00:14:00.469765+0800 iOS_KnowledgeStructure[7940:110114] 2---gogogo 2018-12-27 00:14:00.469873+0800 iOS_KnowledgeStructure[7940:110114] 2---forwardingTargetForSelector: 2018-12-27 00:14:00.469978+0800 iOS_KnowledgeStructure[7940:110114] 3---gogogo 2018-12-27 00:14:00.470097+0800 iOS_KnowledgeStructure[7940:110114] 3---methodSignatureForSelector: 2018-12-27 00:14:00.470247+0800 iOS_KnowledgeStructure[7940:110114] 1---_forwardStackInvocation: 2018-12-27 00:14:00.470355+0800 iOS_KnowledgeStructure[7940:110114] 1---resolveInstanceMethod: 2018-12-27 00:14:00.470765+0800 iOS_KnowledgeStructure[7940:110114] 4---forwardInvocation: 2018-12-27 00:14:00.471367+0800 iOS_KnowledgeStructure[7940:110114] 4-最后一步--<NSInvocation: 0x600002442000> 2018-12-27 00:14:00.471969+0800 iOS_KnowledgeStructure[7940:110114] lalalalala---gogogo
下面就利用消息转发机制,构建装饰器,来实现图像滤镜功能。
科普一下装饰器模式。
图像滤镜的UML类图为:
主要代码实现如下:
mageComponent抽象父类接口设计如下:
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @protocol ZHFImageComponent <NSObject> - (void)drawAtPoint:(CGPoint)point; - (void)drawAtPoint:(CGPoint)point blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha; - (void)drawInRect:(CGRect)rect; - (void)drawInRect:(CGRect)rect blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha; - (void)drawAsPatternInRect:(CGRect)rect; @end NS_ASSUME_NONNULL_END
#import <UIKit/UIKit.h> #import "ZHFImageComponent.h" NS_ASSUME_NONNULL_BEGIN @interface UIImage (ZHFImageComponent) <ZHFImageComponent> @end NS_ASSUME_NONNULL_END
装饰器接口代码如下:
.h文件
#import <Foundation/Foundation.h> #import "ZHFImageComponent.h" NS_ASSUME_NONNULL_BEGIN @interface ZHFImageFilter : NSObject <ZHFImageComponent> { @private id<ZHFImageComponent> component_; } @property (nonatomic, strong) id<ZHFImageComponent> component; - (instancetype)initWithImageComponent:(id<ZHFImageComponent>)component; - (void)apply; - (id)forwardingTargetForSelector:(SEL)aSelector; @end NS_ASSUME_NONNULL_END
.m文件
#import "ZHFImageFilter.h" @implementation ZHFImageFilter @synthesize component = component_; - (instancetype)initWithImageComponent:(id<ZHFImageComponent>)component { if (self = [super init]) { self.component = component; } return self; } - (id)forwardingTargetForSelector:(SEL)aSelector { if ([NSStringFromSelector(aSelector) hasPrefix:@"draw"]) { [self apply]; } //使用消息转发给另一个对象处理,来实现任务处理链条,非常巧妙!!! return component_; } @end
forwardingTargetForSelector方法的实现是整个装饰器的灵魂,子类其实只是调用父类的这个方法而已。
形变装饰器代码如下:
#import "ZHFImageFilter.h" NS_ASSUME_NONNULL_BEGIN @interface ZHFImageTransformFilter : ZHFImageFilter { @private CGAffineTransform transform_; } @property (nonatomic, assign) CGAffineTransform transform; - (instancetype)initWithImageComponent:(id<ZHFImageComponent>)component transform:(CGAffineTransform)transform; @end NS_ASSUME_NONNULL_END #import "ZHFImageTransformFilter.h" @implementation ZHFImageTransformFilter @synthesize transform = transform_; - (instancetype)initWithImageComponent:(id<ZHFImageComponent>)component transform:(CGAffineTransform)transform { if (self = [super initWithImageComponent:component]) { transform_ = transform; } return self; } - (void)apply { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextConcatCTM(context, transform_); } @end
完整的demo实现: https://github.com/zhfei/Objective-C_Design_Patterns