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文件

  1. #import <Foundation/Foundation.h>
  2. @interface SelectorDemo : NSObject
  3. {
  4. SEL _methodTest;
  5. }
  6. @property (nonatomic,assign) SEL methodTest;//这里声明为属性方便在于外部传入。
  7. -(void)TestParentMethod;
  8. -(void)TestSubMethod;
  9. @end

.m文件

  1. #import "SelectorDemo.h"
  2. @implementation SelectorDemo
  3. @synthesize methodTest = _methodTest;
  4. -(void)parentMethod
  5. {
  6. NSLog(@"parent method Call Success!");
  7. }
  8. -(void)TestParentMethod
  9. {
  10. if (_methodTest)
  11. {
  12. [self performSelector:_methodTest withObject:nil];
  13. }
  14. }
  15. -(void)TestSubMethod
  16. {
  17. if (_methodTest)
  18. {
  19. [self performSelector:_methodTest withObject:nil];
  20. }
  21. }
  22. @end

子类:

.h文件

  1. #import <Foundation/Foundation.h>
  2. #import "SelectorDemo.h"
  3. @interface SelectorSub : SelectorDemo
  4. @end

.m文件

  1. #import "SelectorSub.h"
  2. @implementation SelectorSub
  3. -(void)SubMethod
  4. {
  5. NSLog(@"Sub method Call Success!");
  6. }
  7. @end

进行测试调用。

  1. SelectorSub *ss = [[SelectorSub alloc]init];
  2. ss.methodTest = @selector(parentMethod);
  3. [ss TestParentMethod];
  4. ss.methodTest = @selector(SubMethod);
  5. [ss TestParentMethod];
  6. [ss release];

ss.methodTest = @selector(parentMethod); 这句在运行期时,会寻找到父类中的方法进行调用。

ss.methodTest = @selector(SubMethod);//这句就在运行期时,会先寻找父类,如果父类没有,则寻找子类。

如果这里将ss.methodTest = @selector(test); 其中test即不是ss父类,也不是ss本身,也非SS子类,哪么这个时候在使用

[self performSelector:_methodTest withObject:nil];就会出现地址寻找出错 。

  1. 下面的其实是很好的解释为什么必须是自身类或者子类。
  1. [friend performSelector:@selector(gossipAbout:) withObject:aNeighbor];

等价于:

  1. [friend gossipAbout:aNeighbor];
  1. 通过这个原理,当把属性设置为SEL类型时,如果回调机制使用的不是SEL声明的类或子类。想实现其它类的回调,必须传入其它类的上下文句柄。
  1. 举例:
  1. 上面的SelectorDemo 类修改为:
  1. #import <Foundation/Foundation.h>
  2. @interface SelectorDemo : NSObject
  3. {
  4. SEL _methodTest;
  5. id _handle;
  6. }
  7. @property (nonatomic,assign) SEL methodTest;
  8. @property (nonatomic,retain) id handle;        //添加其它类的实例句柄属性。
  9. -(void)TestParentMethod;
  10. -(void)TestSubMethod;
  11. @end
  1. #import "SelectorDemo.h"
  2. @implementation SelectorDemo
  3. @synthesize methodTest = _methodTest;
  4. @synthesize handle = _handle;
  5. -(void)parentMethod
  6. {
  7. NSLog(@"parent method Call Success!");
  8. }
  9. -(void)TestParentMethod
  10. {
  11. if (_methodTest)
  12. {
  13. [_handle performSelector:_methodTest withObject:nil];//这里面原来self属为相应的实例句柄
  14. }
  15. }
  16. -(void)TestSubMethod
  17. {
  18. if (_methodTest)
  19. {
  20. [_handle performSelector:_methodTest withObject:nil];
  21. }
  22. }
  23. @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(接收该消息的对象)进行初始化。

  1. [myButtonCell setAction:@selector(reapTheWind:)];
  2. [myButtonCell setTarget:anObject];

当用户点击了相应的按钮,该按钮单元将使用NSObject协议方法performSelector:withObject:发送消息。所有action消息带有单独一个参数,既发送该消息的控件设备的id。

如果Objective-C不允许改变消息,所有的NSButtonCell对象将不得不发送相同的消息,方法的名字将在NSButtonCell源代码中写死。与简单的实现将用户action转换为action消息的机制不同,按钮单元和其他控件不得不限制消息的内容。受限的消息会使很多对象难以响应多于一个的按钮单元。要么每个按钮有一个target,要么target对象能发现消息来自于那个按钮,并做相应处理。每次在重新布局用户接口时,你也必须实现响应action消息的方法。动态消息的缺乏将会带来不必要的麻烦,但Objective-C很好地避免了这一点。

从前面的例子可以得知如果SEL不是自身的方法,在调用时就会出错,引起CRASH,哪么如何避免消息传递引起的错误。见下文章:

避免消息错误

如果一个对象接收了一条消息去执行不归它管的方法,就会产生错误结果。这和调用一个不存在的函数是同一类错误。但是,因为消息发生在运行时,错误只有在程序执行后才会出现。

当消息选择器是常数并且接收对象类已知时,处理这种错误相对容易。在写程序时,你可以确保接收者能够响应。如果接收者时静态类型,编译器将替你完成该测试。

但是,如果消息选择器或接收者是变化的,那么只能在运行时进行相关测试。NSObject类中定义的respondsToSelector:方法可以测试一个接收者是否能够响应某条消息。它将方法选择器作为参数并返回接收者是否已经访问了与选择器相匹配的一个方法:

  1. if ( [anObject respondsToSelector:@selector(setOrigin::)] )
  2. [anObject setOrigin:0.0 :0.0];
  3. else
  4. fprintf(stderr, "%s can’t be placed\n",
  5. [NSStringFromClass([anObject class]) UTF8String]);

当你向一个你在编译时无法控制的对象发送消息时,respondsToSelector:运行时测试非常重要。例如,如果你写了一段代码向一个对象发送消息,而这个对象是一个他人可以设定值的变量,那么你就要确保接收者实现了响应该消息的方法。

注意:一个对象在收到不是自己负责直接响应的消息时可以转发该消息给其他对象。这种情况下,从调用者的角度来看,对象直接处理了消息,尽管该对象是通过转发消息给其他对象来处理的。

注意2、查找类方法时,除了方法名,方法参数也查询条件之一.

这个主要是多个参数时需要注意,如:

  1. SEL setWidthHeight;
  2. setWidthHeight = @selector(setWidth:height:);

注意3、可以用字符串来找方法 SEL 变量名 = NSSelectorFromString(方法名字的字符串);

注意4、 可以运行中用SEL变量反向查出方法名字字符串,如:NSString *method = NSStringFromSelector(setWidthHeight);

注意5、SEL 查找的方法不支持类方法(即静态方法,在C++中带static关键字的,在OBJECT-C中即方法前带+号的,DELPHI中为class function)。

http://blog.csdn.net/fengsh998/article/details/8612969

IOS SEL (@selector) 原理及使用总结(一)的更多相关文章

  1. IOS SEL (@selector) 原理及使用总结(二)

    SEL消息机制工作原理是什么 引用下面文章: 我们在之前有提到,一个类就像一个 C 结构.NSObject 声明了一个成员变量: isa. 由于 NSObject 是所有类的根类,所以所有的对象都会有 ...

  2. OC SEL (@selector) 原理及使用总结(转)

    SEL 类成员方法的指针 可以理解 @selector()就是取类方法的编号,他的行为基本可以等同C语言的中函数指针,只不过C语言中,可以把函数名直接赋给一个函数指针,而Object-C的类不能直接应 ...

  3. iOS多线程编程原理及实践

    摘要:iOS开发中,开发者不仅要做好iOS的内存管理,而且如果你的iOS涉及多线程,那你也必须了解iOS编程中对多线程的限制,iOS主线程的堆栈大小为1M,其它线程均为512KB,且这个限制开发者是无 ...

  4. iOS开发·runtime原理与实践: 消息转发篇(Message Forwarding) (消息机制,方法未实现+API不兼容奔溃,模拟多继承)...

    本文Demo传送门: MessageForwardingDemo 摘要:编程,只了解原理不行,必须实战才能知道应用场景.本系列尝试阐述runtime相关理论的同时介绍一些实战场景,而本文则是本系列的消 ...

  5. iOS Category实现原理 (补充)

    iOS Category实现原理 (补充) load 和 initialize load load方法会在程序启动就会调用,当装载类信息的时候就会调用. 调用顺序看一下源代码.在 objc-loadm ...

  6. Java NIO系列教程(七) selector原理 Epoll版的Selector

    目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...

  7. iOS程序启动原理---iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 //转载请注明出处--本文永久链接:http://www.cnblogs.com/Ch ...

  8. iOS应用启动原理图解 及ARC强弱引用

    iOS应用启动原理图解(红色箭头表示strong强引用,绿色箭头代表weak若引用) 只要将UI控件拖到Storyboard里控制器的大view上,Xcode会自动将这些控件以强引用的形式加入到sel ...

  9. iOS Category实现原理

    iOS Category实现原理 实现原理 我们不主动引入 Category 的头文件,Category 中的方法都会被添加进主类中.我们可以通过 - performSelector: 等方式 对 C ...

随机推荐

  1. Git 设置 SOCKS 代理

    $ export all_proxy=socks5://127.0.0.1:1080

  2. Java线程池可用的队列

    Java线程池ThreadPoolExecutor的构造器: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long ...

  3. H5唤起app

    H5唤起app 1.判断是否在微信中打开 无论是在哪个平台的客户端Android/IOS,在微信的平台上访问都有一个问题,那就是无法启动客户端,这是微信为了安全性考虑的限制,android这边屏蔽sc ...

  4. 【Jmeter】压测mysql数据库中间件mycat

    背景 因为博主所负责测试的项目需要数据库有较大的吞吐量,在最近进行了升级,更新了一个数据库中间件 - - mycat.查询了一些资料,了解到这是阿里的一个开源项目,基于mysql,是针对磁盘的读与写, ...

  5. wireshark初学者使用

    介绍 Wireshark是一款网络封包分析软件,截取网络封包,显示其封包的详细信息.日常工作中用的比较多.在使用wireshark之前须了解常用的网络协议.如:tcp,http,ip,udp等.(其实 ...

  6. Windows音频SDK的发展历程

    WASAPI is one of several native audio libraries in Windows. PortAudio actually supports five of them ...

  7. nyoj117——树状数组升级版(树状数组+离散化)

    求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5   描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中 ...

  8. struts.xml路径修改后的web配置

    <?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_9" ...

  9. HDU 4283 You Are the One ★(进出栈的括号匹配性质:区间DP)

    题意 有一个队列,每个人有一个愤怒值D,如果他是第K个上场,不开心指数就为(K-1)*D.但是边上有一个小黑屋(一个FILO堆栈),可以一定程度上调整上场程序,求一种安排上场方案使得所有人的不开心指数 ...

  10. RabbitMQ(2) vhost、用户和权限

    rabbitmq中,vhost提供了资源隔离机制.同时,通过为用户设置vhost粒度的权限,可以实现丰富的权限控制功能. vhost 在rabbitmq中,可以创建被称为虚拟主机(vhost)的虚拟消 ...