There are many applications in the dynamic proxy mode, especially when the agent class cannot be modified, it is very convenient to handle some methods, such as logging or capturing exceptions. You only need to modify the client (scenario class) code in a small amount and add a proxy class, which complies with Open-Close Principle.
AOP in Java and. Net also utilizes the implementation of this proxy mode.
The iOS implementation code is as follows:
First, define an interface,
@protocol DPDynamicProtocol <NSObject>@required- (void)doSomething;- (void)doOtherThing;@end
This interface does two things: doSomething and doOtherThing.
The proxy class needs to implement this interface (not actually implemented, but it is not well designed. Every class should implement the interface or inherit from an abstract class ).
#import "DPDynamicProtocol.h"@interface DPNormalObject : NSObject <DPDynamicProtocol>@end
@implementation DPNormalObject- (void)doSomething { NSLog(@"normal object do something");}- (void)doOtherThing { NSLog(@"normal object do other thing");}@end
The proxy class also implements the DPDynamicProtocal interface and inherits from the NSProxy class.
#import "DPDynamicProtocol.h"@interface DPDynamicProxy : NSProxy <DPDynamicProtocol> { @private id<DPDynamicProtocol> _obj;}- (id)initWithObject:(id<DPDynamicProtocol>)obj;@end
@implementation DPDynamicProxy- (id)initWithObject:(id<DPDynamicProtocol>)obj { _obj = obj; return self;}- (void)forwardInvocation:(NSInvocation *)invocation { if (_obj) { NSLog(@"proxy invocation obj method : %s", [invocation selector]); [invocation setTarget:_obj]; [invocation invoke]; }}- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { if ([_obj isKindOfClass:[NSObject class]]) { return [(NSObject *)_obj methodSignatureForSelector:sel]; } return [super methodSignatureForSelector:sel];}- (void)doSomething { NSLog(@"proxy do something");//1 [_obj doSomething];}@end
In this way, you can add logs or catch exceptions before the doSomething method of the proxy class NPNormalObject.
Modify the scenario class:
- (void)clientInvoke {// id<DPDynamicProtocol> obj = [[DPNormalObject alloc] init]; // 2 id<DPDynamicProtocol> obj = [[DPDynamicProxy alloc] initWithObject:[[DPNormalObject alloc] init]]; // 3 [obj doSomething]; [obj doOtherThing];}
You only need to change 2 to 3.