OC SEL (@selector) 原理及使用总结(转)
SEL 类成员方法的指针
可以理解 @selector()就是取类方法的编号,他的行为基本可以等同C语言的中函数指针,只不过C语言中,可以把函数名直接赋给一个函数指针,而Object-C的类不能直接应用函数指针,这样只能做一个@selector语法来取.
它的结果是一个SEL类型。这个类型本质是类方法的编号(函数地址)
C/C++函数指针
int test(int val)
{
return val+1;
}
int (* c_func)(int val); //定义一个函数指针变量c_func = add ; //把函数addr地址直接赋给c_func
object-c的选择器,
@interface foo
-(int)add:int val;
@end
SEL class_func ; //定义一个类方法指针class_func = @selector(add:int);
注意1、@selector是查找当前类(含子类)的方法。
举例:
父类.h文件
- #import <Foundation/Foundation.h>
- @interface SelectorDemo : NSObject
- {
- SEL _methodTest;
- }
- @property (nonatomic,assign) SEL methodTest;//这里声明为属性方便在于外部传入。
- -(void)TestParentMethod;
- -(void)TestSubMethod;
- @end
.m文件
- #import "SelectorDemo.h"
- @implementation SelectorDemo
- @synthesize methodTest = _methodTest;
- -(void)parentMethod
- {
- NSLog(@"parent method Call Success!");
- }
- -(void)TestParentMethod
- {
- if (_methodTest)
- {
- [self performSelector:_methodTest withObject:nil];
- }
- }
- -(void)TestSubMethod
- {
- if (_methodTest)
- {
- [self performSelector:_methodTest withObject:nil];
- }
- }
- @end
子类:
.h文件
- #import <Foundation/Foundation.h>
- #import "SelectorDemo.h"
- @interface SelectorSub : SelectorDemo
- @end
.m文件
- #import "SelectorSub.h"
- @implementation SelectorSub
- -(void)SubMethod
- {
- NSLog(@"Sub method Call Success!");
- }
- @end
进行测试调用。
- SelectorSub *ss = [[SelectorSub alloc]init];
- ss.methodTest = @selector(parentMethod);
- [ss TestParentMethod];
- ss.methodTest = @selector(SubMethod);
- [ss TestParentMethod];
- [ss release];
ss.methodTest = @selector(parentMethod); 这句在运行期时,会寻找到父类中的方法进行调用。
ss.methodTest = @selector(SubMethod);//这句就在运行期时,会先寻找父类,如果父类没有,则寻找子类。
如果这里将ss.methodTest = @selector(test); 其中test即不是ss父类,也不是ss本身,也非SS子类,哪么这个时候在使用
[self performSelector:_methodTest withObject:nil];就会出现地址寻找出错 。
- 下面的其实是很好的解释为什么必须是自身类或者子类。
- [friend performSelector:@selector(gossipAbout:) withObject:aNeighbor];
等价于:
- [friend gossipAbout:aNeighbor];
- 通过这个原理,当把属性设置为SEL类型时,如果回调机制使用的不是SEL声明的类或子类。想实现其它类的回调,必须传入其它类的上下文句柄。
- 举例:
- 上面的SelectorDemo 类修改为:
- #import <Foundation/Foundation.h>
- @interface SelectorDemo : NSObject
- {
- SEL _methodTest;
- id _handle;
- }
- @property (nonatomic,assign) SEL methodTest;
- @property (nonatomic,retain) id handle; //添加其它类的实例句柄属性。
- -(void)TestParentMethod;
- -(void)TestSubMethod;
- @end
- #import "SelectorDemo.h"
- @implementation SelectorDemo
- @synthesize methodTest = _methodTest;
- @synthesize handle = _handle;
- -(void)parentMethod
- {
- NSLog(@"parent method Call Success!");
- }
- -(void)TestParentMethod
- {
- if (_methodTest)
- {
- [_handle performSelector:_methodTest withObject:nil];//这里面原来self属为相应的实例句柄
- }
- }
- -(void)TestSubMethod
- {
- if (_methodTest)
- {
- [_handle performSelector:_methodTest withObject:nil];
- }
- }
- @end
到这里我想熟悉IOS,target-action模式的,都清晰了。
Target-Action设计模式
在处理用户-接口控件方面,AppKit充分发挥了在运行时改变接收者和消息的能力。
NSControl对象是一个图形设备,可以用来向应用程序发送指令,。大多实现了现实世界中的控制装置,例如button、switch、knob、text field、dial、menu item等。在软件中,这些设备处于用户和和应用程序之间。它们解释来自硬件设备,如键盘和鼠标的事件,并将它们翻译成应用程序特定的指令。例如,名为“Find”的按钮将会把鼠标点击事件翻译成开始搜索的应用程序指令。
AppKit为创建控件设备定义了模板,并定义了一些自己的现成设备。例如,NSButtonCell类定义了一个对象,可以指派给一个NSMatrix实例,并初始化它的大小、名称、图片、字体和键盘快捷键。当用户点击按钮(或使用键盘快捷键)时,NSButtonCell对象发送消息,指示应用程序工作。为此,NSButtonCell对象不仅要初始化图像、大小和名称,还要确定消息要发往何方和发给谁。相应地,NSButtonCell实例可以为一个action消息(它将在自己发送的消息中使用的对象选择器)和一个target(接收该消息的对象)进行初始化。
- [myButtonCell setAction:@selector(reapTheWind:)];
- [myButtonCell setTarget:anObject];
当用户点击了相应的按钮,该按钮单元将使用NSObject协议方法performSelector:withObject:发送消息。所有action消息带有单独一个参数,既发送该消息的控件设备的id。
如果Objective-C不允许改变消息,所有的NSButtonCell对象将不得不发送相同的消息,方法的名字将在NSButtonCell源代码中写死。与简单的实现将用户action转换为action消息的机制不同,按钮单元和其他控件不得不限制消息的内容。受限的消息会使很多对象难以响应多于一个的按钮单元。要么每个按钮有一个target,要么target对象能发现消息来自于那个按钮,并做相应处理。每次在重新布局用户接口时,你也必须实现响应action消息的方法。动态消息的缺乏将会带来不必要的麻烦,但Objective-C很好地避免了这一点。
从前面的例子可以得知如果SEL不是自身的方法,在调用时就会出错,引起CRASH,哪么如何避免消息传递引起的错误。见下文章:
避免消息错误
如果一个对象接收了一条消息去执行不归它管的方法,就会产生错误结果。这和调用一个不存在的函数是同一类错误。但是,因为消息发生在运行时,错误只有在程序执行后才会出现。
当消息选择器是常数并且接收对象类已知时,处理这种错误相对容易。在写程序时,你可以确保接收者能够响应。如果接收者时静态类型,编译器将替你完成该测试。
但是,如果消息选择器或接收者是变化的,那么只能在运行时进行相关测试。NSObject类中定义的respondsToSelector:方法可以测试一个接收者是否能够响应某条消息。它将方法选择器作为参数并返回接收者是否已经访问了与选择器相匹配的一个方法:
- if ( [anObject respondsToSelector:@selector(setOrigin::)] )
- [anObject setOrigin:0.0 :0.0];
- else
- fprintf(stderr, "%s can’t be placed\n",
- [NSStringFromClass([anObject class]) UTF8String]);
当你向一个你在编译时无法控制的对象发送消息时,respondsToSelector:运行时测试非常重要。例如,如果你写了一段代码向一个对象发送消息,而这个对象是一个他人可以设定值的变量,那么你就要确保接收者实现了响应该消息的方法。
注意:一个对象在收到不是自己负责直接响应的消息时可以转发该消息给其他对象。这种情况下,从调用者的角度来看,对象直接处理了消息,尽管该对象是通过转发消息给其他对象来处理的。
注意2、查找类方法时,除了方法名,方法参数也查询条件之一.
这个主要是多个参数时需要注意,如:
- SEL setWidthHeight;
- setWidthHeight = @selector(setWidth:height:);
注意3、可以用字符串来找方法 SEL 变量名 = NSSelectorFromString(方法名字的字符串);
注意4、 可以运行中用SEL变量反向查出方法名字字符串,如:NSString *method = NSStringFromSelector(setWidthHeight);
注意5、SEL 查找的方法不支持类方法(即静态方法,在C++中带static关键字的,在OBJECT-C中即方法前带+号的,DELPHI中为class function)。
OC SEL (@selector) 原理及使用总结(转)的更多相关文章
- IOS SEL (@selector) 原理及使用总结(二)
SEL消息机制工作原理是什么 引用下面文章: 我们在之前有提到,一个类就像一个 C 结构.NSObject 声明了一个成员变量: isa. 由于 NSObject 是所有类的根类,所以所有的对象都会有 ...
- IOS SEL (@selector) 原理及使用总结(一)
SEL 类成员方法的指针 可以理解 @selector()就是取类方法的编号,他的行为基本可以等同C语言的中函数指针,只不过C语言中,可以把函数名直接赋给一个函数指针,而Object-C的类不能直接应 ...
- Java NIO系列教程(七) selector原理 Epoll版的Selector
目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...
- OC - KVO实现原理
1.KVO简介 KVO是Objective-C对观察者设计模式的一种实现,它提供一种机制,指定一个被观察对象(如A类),当对象中的某个属性发生变化的时候,对象就会接收到通知,并作出相应的处理.在MVC ...
- Android Selector原理
android的selector对于android开发者而言再熟悉不过了,只要定义一个drawable目录下定义一个selector的xml文件,在布局文件中引用这个xml文件或者在代码中setBac ...
- 42 (OC)* 字典实现原理--哈希原理
一.NSDictionary使用原理 1.NSDictionary(字典)是使用 hash表来实现key和value之间的映射和存储的,hash函数设计的好坏影响着数据的查找访问效率. - (void ...
- OC - 17.AFNetworking原理及常用操作
AFN的六大模块 NSURLConnection,主要对NSURLConnection进行了进一步的封装,包含以下核心的类: AFURLConnectionOperation AFHTTPReques ...
- oc引用计数原理-引用计数相关变化
http://blog.csdn.net/null29/article/details/71191044 在 32 位环境下,对象的引用计数都保存在一个外部的表中,每一个对象的 Retain 操作,实 ...
- ***iOS开发中@selector的理解与应用
@selector 是什么? 1一种类型 SEL2代表你要发送的消息(方法), 跟字符串有点像, 也可以互转.: NSSelectorFromString() / NSSelectorFromStri ...
随机推荐
- HBASE学习d端口master:16010(java操作hbase)https://www.cnblogs.com/junrong624/p/7323483.html
HBase提示已创建表,但是list查询时,却显示表不存在. https://blog.csdn.net/liu16659/article/details/80216085 下载网址 http://a ...
- VC:GetWindowRect、GetClientRect、ScreenToClient与ClientToScreen
GetWindowRect是取得窗口在屏幕坐标系下的RECT坐标(包括客户区和非客户区),这样可以得到窗口的大小和相对屏幕左上角(0,0)的位置. GetClientRect取得窗口客户区(不包括非客 ...
- C++对象的virtual table在内存中的布局
(1)单一继承 (2)多重继承 (3)虚拟继承 参考:<深度探索C++对象模型>
- java反射的补充:桥接方法以及Spring中一些工具类
在上一篇博文中:http://www.cnblogs.com/guangshan/p/4660564.html 源码中有些地方用到了 this.bridgedMethod = BridgeMethod ...
- var 在linq中的使用
一:掌握linq,写出超炫的代码 1. var关键字 [隐式类型] 隐式类型 和 匿名类型的不同叫法. 特性 和 属性 2.隐式类型 就是让编译器来推断的一种语法糖. 二:隐式类型的应用场景 1. 简 ...
- Ocelot Consul
1首先创建一个json的配置文件,文件名随便取,我取Ocelot.json 这个配置文件有两种配置方式,第一种,手动填写 服务所在的ip和端口:第二种,用Consul进行服务发现 第一种如下: { & ...
- Https&证书
参考 http站点转https站点教程 http站点转https站点教程 HTTP与HTTPS的区别 Http站点转为Https: 为域名购买/申请证书(免费型DV SSL) 把证书部署到web se ...
- Entity Framework 6 暂停重试执行策略
EF6引入一个弹性连接的功能,也就是允许重新尝试执行失败的数据库操作.某些复杂的场景中,可能需要启用或停用重试执行的策略,但是EF框架暂时尚未提供直接的设置开关,将来可能会加入这种配置.幸运的是,很容 ...
- 聊聊 JDK 非阻塞队列源码(CAS实现)
正如上篇文章聊聊 JDK 阻塞队列源码(ReentrantLock实现)所说,队列在我们现实生活中队列随处可见,最经典的就是去银行办理业务,超市买东西排队等.今天楼主要讲的就是JDK中安全队列的另一种 ...
- 为什么 SQLite 用 C 编写?
简评:SQLite 官方出品. C是最好的选择 从 2000 年 5 月 29 日开始,SQLite 就选择了 C 语言.直到今天,C 也是实现 SQLite 这样软件库的最佳语言. C语言是实现 S ...