#import <Foundation/Foundation.h> @interface MyInvoc : NSObject { NSString* _name; } -(NSInteger) myLen:(NSString*) aStr; -(NSMethodSignature*) methodSignatureForSelector:(SEL)aSelector; -(void)forwardInvocation:(NSInvocation *)anInvocation; @end
#import "MyInvoc.h" @implementation MyInvoc { NSMutableDictionary* _dic; } -(id)init { if (self = [super init]) { _name = [[NSString alloc] init]; _name = @"hello"; _dic = [[NSMutableDictionary alloc] init]; } return self; } -(NSInteger) myLen:(NSString *)aStr { return [aStr length]; } -(NSMethodSignature*) methodSignatureForSelector:(SEL)aSelector { NSMethodSignature* Msignature =[super methodSignatureForSelector:aSelector]; if (!Msignature) { NSString* MethodName = NSStringFromSelector(aSelector); if ([MethodName rangeOfString:@"set"].location == 0) { Msignature = [NSMethodSignature signatureWithObjCTypes:"v@:@"]; //v@:@ v:返回值类型void;@ id类型,执行sel的对象;:SEL;@参数 } else { if ([MethodName compare:@"length"] == NSOrderedSame) { Msignature = [_name methodSignatureForSelector:aSelector]; } else{ Msignature =[NSMethodSignature signatureWithObjCTypes:"@@:"]; //@:返回值类型id;@id类型,执行sel的对象;:SEL; } } } return Msignature; } -(void)forwardInvocation:(NSInvocation *)anInvocation { NSString* MethodName = NSStringFromSelector([anInvocation selector]); if ([MethodName rangeOfString:@"set"].location == 0) { NSString* key = [[MethodName substringWithRange:NSMakeRange(3, [MethodName length] - 4)] lowercaseString]; id obj; [anInvocation getArgument:&obj atIndex:2]; [_dic setObject:obj forKey:key]; } else{ if ([MethodName compare:@"length"] == NSOrderedSame) { [anInvocation invokeWithTarget:_name]; } else { id obj = [_dic objectForKey:MethodName]; [anInvocation setReturnValue:&obj]; } } } @end
#import "ViewController.h" #import "MyInvoc.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; id m = [[MyInvoc alloc] init]; //注意点1:执行的方法最好能找到,利用sel声明变量虽然也能用,但有警告。 [m setName: @"hello"]; NSLog(@"name is %@, length is %ld",[m name], [m length]); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
总结
1,sel与nsstring的转换系统提供了两个函数,特别方便。nsstringfromselector,nsselectorfromstring;
2,调用没有找到的函数时才会进入获取签名函数。
3,[aninvocation invokeWithTarget:_name],这里的taget是能够执行这个签名的函数的对象。