NSProxy与NSObject的区别
代理类NSProxy,就是通过向外暴露Proxy类,来达到屏蔽内部使用的具体类。 NSProxy没有init方法,天生就是用来做代理的。
NSProxy与NSObject很相似,但是通过继承自NSObject的代理类是不会自动转发respondsToSelector:
和isKindOfClass:
这两个方法(就是调用这两个方法不会经过消息转发), 而继承自NSProxy的代理类却是可以的。因为NSObject有定义respondsToSelector与isKindOfClass。而 NSProxy没有。
NSProxy确实更适合实现做为消息转发的代理类, 因为作为一个抽象类, NSProxy自身能够处理的方法极小(仅接口中定义的部分方法), 所以其它方法都能够按照设计的预期被转发到被代理的对象中.
抽一个抽象协议接口,用来抽象某一类事物.
Animal.h 代表动物这一类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #import <Foundation/Foundation.h>
/** * 一个动物的所有行为的抽象 */ @protocol Animal <NSObject>
/** * 动物的名字 */ - (NSString *)name;
/** * 动物的类型 */ - (NSString *)type;
/** * 叫 */ - (void)call;
/** * 跑步 */ - (void)run;
@end
|
接下来那么就是接口实现咯,简单两个实现类 Dog 和 Cat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #import <Foundation/Foundation.h> #import "Animal.h"
@interface Dog : NSObject <Animal>
@end
#import "Dog.h"
@implementation Dog
- (NSString *)name { return @"狗"; }
- (NSString *)type { return @"哺乳动物"; }
- (void)call { NSLog(@"狗在叫..."); }
- (void)run { NSLog(@"狗在跑..."); }
@end
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #import <Foundation/Foundation.h> #import "Animal.h"
@interface Cat : NSObject <Animal>
@end #import "Cat.h"
@implementation Cat
- (NSString *)name { return @"猫"; }
- (NSString *)type { return @"哺乳动物"; }
- (void)call { NSLog(@"猫在叫..."); }
- (void)run { NSLog(@"猫在跑..."); }
@end
|
AnimalProxy类,作为所有Animal这一类对象的代理对象
AnimalProxy.h
1 2 3 4 5 6 7 8 9 10 11 12
| #import <Foundation/Foundation.h> #import "Animal.h"
/** * 专门用来做Animal这一类对象的代理 * 代理也实现Animal协议 */ @interface AnimalProxy : NSProxy <Animal>
+ (instancetype)animalWithType:(NSString *)type;
@end
|
AnimalProxy.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| #import "AnimalProxy.h" #import <objc/runtime.h>
#import "Dog.h" #import "Cat.h"
@interface AnimalProxy ()
@property (nonatomic,strong) NSMutableDictionary *selHandlerDict;
@end
@implementation AnimalProxy
+ (instancetype)animalWithType:(NSString *)type { //NSProxy没有init方法 AnimalProxy *_sharedProxy = [AnimalProxy alloc];
//创建SEL与接口实现对象的关联 _sharedProxy.selHandlerDict = [NSMutableDictionary dictionary];
Class animalClass = NSClassFromString(type);
//绑定 协议 与 具体实现类对象 [_sharedProxy _registerHandlerProtocol:@protocol(Animal) handler:[animalClass new]]; // [_sharedProxy _registerHandlerProtocol:@protocol(Animal) handler:[Cat new]];
return _sharedProxy; }
- (void)_registerHandlerProtocol:(Protocol *)protocol handler:(id)handler {
//记录protocol中的方法个数 unsigned int numberOfMethods = 0;
//获取protocol中定义的方法描述 struct objc_method_description *methods = protocol_copyMethodDescriptionList(protocol, YES,//是否必须实现 YES,//是否对象方法 &numberOfMethods);
//遍历所有的方法描述,设置其Target对象 for (unsigned int i = 0; i < numberOfMethods; i++) {
//方法描述结构体实例 struct objc_method_description method = methods[i];
//方法的名字 NSString *methodNameStr = NSStringFromSelector(method.name);
//保存所有方法名对应的Target对象,最终接收处理消息 [_selHandlerDict setValue:handler forKey:methodNameStr]; } }
- (void)forwardInvocation:(NSInvocation *)invocation {
//获取当前触发消息的SEL SEL sel = invocation.selector;
//SEL的字符串 NSString *methodNameStr = NSStringFromSelector(sel);
//SEL字符串查询字典得到保存的消息接收者Target id target = [_selHandlerDict objectForKey:methodNameStr];
//是否找到了要转发SEL执行的Target if (target && [target respondsToSelector:sel]) { //找到Target,就让Target处理消息 [invocation invokeWithTarget:target];
} else {
//未找到Target 或 Target未实现方法,交给super去转发消息 [super forwardInvocation:invocation]; } }
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
//SEL的字符串 NSString *methodNameStr = NSStringFromSelector(sel);
//SEL字符串查询字典得到保存的消息接收者Target id target = [_selHandlerDict objectForKey:methodNameStr];
//是否找到了要转发SEL执行的Target if (target && [target respondsToSelector:sel]) {
//找到了Target,那么获取找到的Target的SEL对应的方法签名 return [target methodSignatureForSelector:sel];
} else {
//未找到Target 或 Target未实现方法,交给super return [super methodSignatureForSelector:sel]; } }
@end
|
调用代理类
1 2 3 4 5 6 7 8 9 10 11 12
| - (void)viewDidLoad { [super viewDidLoad];
AnimalProxy *animalProxy = [AnimalProxy animalWithType:@"Dog"]; NSLog(@"name = %@", [animalProxy name]); NSLog(@"type = %@", [animalProxy type]);
[animalProxy call]; [animalProxy run];
}
|
如果要换成 cat,则只需要调用 [AnimalProxy animalWithType:@”Cat”];