iOS中可以直接调用 某个对象的消息
来源:互联网 发布:机甲世纪革新版数据 编辑:程序博客网 时间:2024/05/17 23:52
在 iOS中可以直接调用 某个对象的消息 方式有3种
1.performSelector:withObject:
2.NSInvocation
3.objc_msgSend
performSelector:withObject:
方式比较简单,能完成简单的调用。但是对于>2个的参数或者有返回值的处理,那就需要做些额外工作才能搞定.
@interface MyClass : NSObject@end
@implementation MyClass-(NSString *)methodNoParameters{ NSLog(@"methodNoParameters"); return @"methodNoParameters";}-(NSString *)methodOneParameters:(NSString *)first{ NSLog(@"methodOneParameters:%@",first); return @"methodOneParameters";}-(NSString *)methodTwoParameters:(NSString *)first two:(NSString *)two{ NSLog(@"methodTwoParameters:%@:%@",first,two); return @"methodTwoParameters";}-(NSString *)methodThreeParameters:(NSString *)first two:(NSString *)two three:(NSString *)three{ NSLog(@"firstMethod:%@:%@:%@",first,two,three); return @"methodThreeParameters";}
- (void)viewDidLoad { [super viewDidLoad]; [self callMethod]; // Do any additional setup after loading the view, typically from a nib.}
<pre name="code" class="objc">-(void)callMethod{ MyClass *object = [[MyClass alloc] init]; NSString *returnValue = [object performSelector:@selector(methodNoParameters)]; NSLog(@"return:%@",returnValue); returnValue = [object performSelector:@selector(methodOneParameters:) withObject:@"firstParermater"]; NSLog(@"return:%@",returnValue); returnValue = [object performSelector:@selector(methodTwoParameters:two:) withObject:@"firstParermater" withObject:@"SecondParameter"]; NSLog(@"return:%@",returnValue);}
2015-06-16 12:05:03.396 Demo[7877:138875] methodNoParameters2015-06-16 12:05:03.396 Demo[7877:138875] return:methodNoParameters2015-06-16 12:05:03.397 Demo[7877:138875] methodOneParameters:firstParermater2015-06-16 12:05:03.397 Demo[7877:138875] return:methodOneParameters2015-06-16 12:05:03.397 Demo[7877:138875] methodTwoParameters:firstParermater:SecondParameter2015-06-16 12:05:03.397 Demo[7877:138875] return:methodTwoParameters
NSInvocation
NSInvocation可以处理参数、返回值。其实NSInvocation就相当于反射操作<pre name="code" class="objc">- (void)viewDidLoad { [super viewDidLoad]; [self callInvocation]; // Do any additional setup after loading the view, typically from a nib.}
-(void)callInvocation{ MyClass *object = [[MyClass alloc] init]; NSMethodSignature *methodSig = [object methodSignatureForSelector:@selector(methodNoParameters)]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig]; [invocation setTarget:object]; [invocation setSelector:@selector(methodNoParameters)]; [invocation invoke]; methodSig = [object methodSignatureForSelector:@selector(methodThreeParameters:two:three:)]; invocation = [NSInvocation invocationWithMethodSignature:methodSig]; [invocation setTarget:object]; [invocation setSelector:@selector(methodThreeParameters:two:three:)]; NSString *firstArgu = @"first"; [invocation setArgument:&firstArgu atIndex:2]; NSString *secondArgu = @"second"; [invocation setArgument:&secondArgu atIndex:3]; NSString *thirdArgu = @"third"; [invocation setArgument:&thirdArgu atIndex:4]; [invocation invoke]; [invocation retainArguments]; //get return value const char *returnType = methodSig.methodReturnType; id returnValue; if (!strcmp(returnType,@encode(void))) { returnValue = nil; }else if (!strcmp(returnType, @encode(id))){ [invocation getReturnValue:&returnValue]; }else{ //如果返回值为普通类型NSInteger BOOL //返回值长度 NSUInteger length = [methodSig methodReturnLength]; //根据长度申请内存 void *buffer = (void *)malloc(length); //为变量赋值 [invocation getReturnValue:buffer]; if( !strcmp(returnType, @encode(BOOL))) { returnValue = [NSNumber numberWithBool:*((BOOL*)buffer)]; }else if( !strcmp(returnType, @encode(NSInteger)) ){ returnValue = [NSNumber numberWithInteger:*((NSInteger*)buffer)]; }else{ returnValue = [NSValue valueWithBytes:buffer objCType:returnType]; } free(buffer); } NSLog(@"return:%@",returnValue); }
2015-06-16 12:05:28.936 Demo[7877:138875] methodNoParameters2015-06-16 12:05:28.936 Demo[7877:138875] firstMethod:first:second:third2015-06-16 12:05:28.937 Demo[7877:138875] return:methodThreeParameters
objc_msgSend
在Objective-C中,message与方法的真正实现是在执行阶段绑定的,而非编译阶段。编译器会将消息发送转换成对objc_msgSend方法的调用。 objc_msgSend方法含两个必要参数:receiver、方法名(即:selector),如: [receiver message]; 将被转换为:objc_msgSend(receiver, selector); objc_msgSend方法也能hold住message的参数,如: objc_msgSend(receiver, selector, arg1, arg2, …);objc_msgSend方法会做按照顺序进行以下操作,以完成动态绑定:- 查找selector所指代的程序(方法的真正实现)。因为不同类对同一方法有不同的实现,所以对方法的真正实现的查找依赖于receiver的类
- 调用该实现,并将一系列参数传递过去
- 将该实现的返回值作为自己的返回值,返回之
消息传递的关键是,编译器构建每个类和对象时所采用的数据结构。每个类都包含以下两个必要元素:- 一个指向父类的指针
- 一个调度表(dispatch table)。该调度表将类的selector与方法的实际内存地址关联起来
每个对象都有一个指向所属类的指针isa。通过该指针,对象可以找到它所属的类,也就找到了其全部父类,如下图所示: 当向一个对象发送消息时,objc_msgSend方法根据对象的isa指针找到对象的类,然后在类的调度表(dispatch table)中查找selector。如果无法找到selector,objc_msgSend通过指向父类的指针找到父类,并在父类的调度表(dispatch table)中查找selector,以此类推直到NSObject类。一旦查找到selector,objc_msgSend方法根据调度表的内存地址调用该实现。 通过这种方式,message与方法的真正实现在执行阶段才绑定。 为了保证消息发送与执行的效率,系统会将全部selector和使用过的方法的内存地址缓存起来。每个类都有一个独立的缓存,缓存包含有当前类自己的 selector以及继承自父类的selector。查找调度表(dispatch table)前,消息发送系统首先检查receiver对象的缓存。 缓存命中的情况下,消息发送(messaging)比直接调用方法(function call)只慢一点点点点。
关于Selector,什么 是Selector,Selector就是一个字符串,用来表示一个方法。
在Objective-C中,消息是直到运行的时候才和方法实现绑定的。编译器会把一个消息表达式,
[receiver message]
转换成一个对消息函数objc_msgSend的调用。该函数有两个主要参数:消息接收者和消息对应的方法名字——也就是方法选标:
objc_msgSend(receiver, selector)
同时接收消息中的任意数目的参数:
objc_msgSend(receiver, selector, arg1, arg2, ...)
该消息函数做了动态绑定所需要的一切:
它首先找到选标所对应的方法实现。因为不同的类对同一方法可能会有不同的实现,所以找到的方法实现依赖于消息接收者的类型。
然后将消息接收者对象(指向消息接收者对象的指针)以及方法中指定的参数传给找到的方法实现。
最后,将方法实现的返回值作为该函数的返回值返回。
<span style="font-family:SimSun;font-size:14px;">- (void)viewDidLoad { [super viewDidLoad]; [self callMsgSend]; // Do any additional setup after loading the view, typically from a nib.}-(void)callMsgSend{ MyClass *object = [[MyClass alloc] init]; NSString *returnValue = objc_msgSend(object,@selector(methodThreeParameters:two:three:),@"first",@"second",@"third"); NSLog(@"return:%@",returnValue);}</span>
<pre name="code" class="objc"><span style="font-family:SimSun;font-size:14px;">2015-06-16 12:06:54.885 Demo[7877:138875] firstMethod:first:second:third2015-06-16 12:06:54.885 Demo[7877:138875] return:methodThreeParameters</span>
- 查找selector所指代的程序(方法的真正实现)。因为不同类对同一方法有不同的实现,所以对方法的真正实现的查找依赖于receiver的类
- 调用该实现,并将一系列参数传递过去
- 将该实现的返回值作为自己的返回值,返回之
消息传递的关键是,编译器构建每个类和对象时所采用的数据结构。每个类都包含以下两个必要元素:- 一个指向父类的指针
- 一个调度表(dispatch table)。该调度表将类的selector与方法的实际内存地址关联起来
每个对象都有一个指向所属类的指针isa。通过该指针,对象可以找到它所属的类,也就找到了其全部父类,如下图所示:
当向一个对象发送消息时,objc_msgSend方法根据对象的isa指针找到对象的类,然后在类的调度表(dispatch table)中查找selector。如果无法找到selector,objc_msgSend通过指向父类的指针找到父类,并在父类的调度表(dispatch table)中查找selector,以此类推直到NSObject类。一旦查找到selector,objc_msgSend方法根据调度表的内存地址调用该实现。 通过这种方式,message与方法的真正实现在执行阶段才绑定。
为了保证消息发送与执行的效率,系统会将全部selector和使用过的方法的内存地址缓存起来。每个类都有一个独立的缓存,缓存包含有当前类自己的 selector以及继承自父类的selector。查找调度表(dispatch table)前,消息发送系统首先检查receiver对象的缓存。
缓存命中的情况下,消息发送(messaging)比直接调用方法(function call)只慢一点点点点。
关于Selector,什么 是Selector,Selector就是一个字符串,用来表示一个方法。
在Objective-C中,消息是直到运行的时候才和方法实现绑定的。编译器会把一个消息表达式,
[receiver message]
转换成一个对消息函数objc_msgSend的调用。该函数有两个主要参数:消息接收者和消息对应的方法名字——也就是方法选标:
objc_msgSend(receiver, selector)
同时接收消息中的任意数目的参数:
objc_msgSend(receiver, selector, arg1, arg2, ...)
该消息函数做了动态绑定所需要的一切:
它首先找到选标所对应的方法实现。因为不同的类对同一方法可能会有不同的实现,所以找到的方法实现依赖于消息接收者的类型。
然后将消息接收者对象(指向消息接收者对象的指针)以及方法中指定的参数传给找到的方法实现。
最后,将方法实现的返回值作为该函数的返回值返回。
<span style="font-family:SimSun;font-size:14px;">- (void)viewDidLoad { [super viewDidLoad]; [self callMsgSend]; // Do any additional setup after loading the view, typically from a nib.}-(void)callMsgSend{ MyClass *object = [[MyClass alloc] init]; NSString *returnValue = objc_msgSend(object,@selector(methodThreeParameters:two:three:),@"first",@"second",@"third"); NSLog(@"return:%@",returnValue);}</span>
<pre name="code" class="objc"><span style="font-family:SimSun;font-size:14px;">2015-06-16 12:06:54.885 Demo[7877:138875] firstMethod:first:second:third2015-06-16 12:06:54.885 Demo[7877:138875] return:methodThreeParameters</span>
0 0
- iOS中可以直接调用 某个对象的消息
- NSInvocation直接调用某个对象的消息
- 当request.setAtrrbute("存储对象","对象")存储是对象的时候,并且对象中有方法是集合,可以直接到网页中调用方法么?
- 【#include<algorithm>】中包含的可以直接调用的函数
- iOS判断某个类是否可以调用某个类方法
- C++中构造函数居然是可以直接调用的
- C++中构造函数居然是可以直接调用的
- freemarker中页面直接可以使用的内置对象
- freemarker中页面直接可以使用的内置对象
- Freemarker中页面直接可以运用的内置对象
- ios 中调用函数的方法是消息传递,这个和普通的函数调用的区别是,你可以随时对一个对象传递任何消息,而不需要在编译的时候声明这些方法。所以Objective-C可以在runtime的时候
- struts开发中可以在消息资源中直接写中文的东东
- 黑马程序员 static的类可以用类名直接调用,无需创建对象
- 87.直接向对象发送消息和通过performSelector调用的区别
- C#可以直接调用的Win32API
- 某个html页面中,head中的一个js可以调用另一个js的函数吗?
- 直接比较两个对象是否相等返回false和List中判断是否包含某个对象的问题
- 网页直接调用android客户端的某个功能
- JDBC操作事务
- eclipse打开当前文件所在文件夹的两种方法
- 在eclipse中添加open explorer功能
- Java通过JDBC连接MySql数据库
- Ext.Ajax.request 用法参数介绍
- iOS中可以直接调用 某个对象的消息
- Android—ViewPager实现左右循环
- 编程语言中的变量
- 初学linux
- 多线程 handle
- NYOJ 86 找球号(一)
- SpringMVC入门学习(三)+Spring应用(整合)
- 通过httpClient发送json格式数据请求
- C++运算符重载的实现