在Objective-C中,选择器(selector)有两个意思。 一是指在代码中的方法的名称。二是指在编译是用于替换方法名称的唯一的标识符。编译后的选择器的为SEL类型。所有名称相同的方法拥有同一个选择器。通过使用选择器可以调用对象的一个方法。这是Cocoa中目标-动作这一模式能得以实现的基础。

方法和选择器

出于效率的考虑,编译后的代码中并不是使用ASCII码表示的方法名称来作为方法的选择器的。编译器会把每一个方法的名称写入到一张表中;然后用唯一的一个标识符与之结对,这样来表示运行时的方法。运行时系统确保了这种标识符的唯一性:不会出现相同的两个选择器;所有名称相同的方法有用唯一同一个选择器。

SEL和@selector

编译的选择器拥有一种特殊的类型:SEL,以便和其它的数据类型进行区分。有效的选择器都是非0值的。对SEL类型的赋值必须由系统进行;其他的赋值方式都是无益的。
        指令@selector()表示使用编译的选择器,而不是完整的方法名称。如下,setWidth:height:的选择器被赋值给了setWidthHeight变量:
SEL setWidthHeight;
setWidthHiehgt = @selector(setWidth:height:);
         在编译时使用@selector指令来给SEL类型的变量赋值是效率最高的。然而,在某些情况下,可能需要将字符串转换成运行时的选择器。此时可以使用NSSelectorFromString函数来完成:
setWidthHeight = NSSelectorFromString(aBuffer);
        反向的转换也是可以的。函数NSStringFromSelector返回一个选择器对应的方法名称:

  1. NSString * method;
  2. method = NSStringFromSelector(setWidthHeight);

 

方法和选择器

编译的选择器是以方法名称为区分的,而不是以方法的实现。一个类中的display方法的选择器和另外类中的display方法的选择器是同一个。这点对于多态性和动态绑定来说是非常重要的。这使得我们可以为不同类的对象发送相同的消息。如果不同的方法实现对应的是不同的选择器,那么消息和函数调用将没有什么区别。相同名称的类方法和实例方法对应的选择器也是同一个。然后由于两者的作用域是不同的,因此这不会造成冲突。一个类中是可以同时定义display类方法和display实例方法的。

方法的返回值及其参数的类型

        发送消息的例行程序只有通过选择器才能访问方法的实现。因此,它处理所有相同名称的方法的选择器的方式是一样的。它能够从选择器中判断方法的返回值及其参数的类型。因此,除了向静态类型的接收者发送消息之外,动态绑定要求所有名称相同的方法必须具有相同的返回值和参数类型。(静态类型的接收者是个例外,因为在编译时就可以从对应的类中感知到方法的具体实现。)

尽管名称完全一样的类方法和实例方法拥有相同的选择器,它们的参数和返回值的类型可以是不同的。

运行时发送可变消息

NSObject协议中定义的performSelector:,performSelector:WithObject:,performSelector:withObject:withObject:方法都是接收一个SEL类型的变量作为其第一个参数。这三个方法都是直接把消息映射为对应的函数。例如:[friend performSelector:@selector(gossipAbout:) withObject:aNeighbot];和下面的语句是等价的:[friend gossipAbout:aNeighbot];上面的三个方法使得我们可以再运行时发送不同的消息。这正如和运行时接收消息的对象是可变的一样。在发送消息的表达式中,接收者和消息都可以是变量:

  1. id helper = getTheReceiver();
  2. SEL request = getTheSelector();
  3. [helper performSelector:request];

在上面的示例程序中,接收者(helper)是在运行时通过一个假定的函数getTheReceiver而动态选择的;要执行的方法(request)同样也是在运行时通过函数getTheSelector来动态决定的。

译者注:从上面的示例中可以看出,接收消息的对象和发送的具体消息在运行时都是可变的。所以可变消息指的就是上面的这种可变性,而不仅仅局限于发送的消息是可变的。

注意:

performSelector:及其他的方法的返回值类型都是id。如果执行方法的返回值类型不是id类型,则应该对其进行适当的转换。强制的类型转换并不是对所有类型都适用的。执行方法的返回值应该是指针或者是和指针相兼容的类型。

SEL方法选择器的更多相关文章

  1. ios runtime部分事例方法说明

    一.场景--动态改变变量 unsigned ; Ivar *ivar = class_copyIvarList([self.person class], &count); ; i<cou ...

  2. SEL-消息机制

    int main() { Person *p = [[Person alloc] init]; //调用方法 [p test2]; [p performSelector:@selector(test2 ...

  3. Objective-C总Runtime的那点事儿(一)消息机制

    最近在找工作,Objective-C中的Runtime是经常被问到的一个问题,几乎是面试大公司必问的一个问题.当然还有一些其他问题也几乎必问,例 如:RunLoop,Block,内存管理等.其他的问题 ...

  4. iOS运行时Runtime浅析

    运行时是iOS中一个很重要的概念,iOS运行过程中都会被转化为runtime的C代码执行.例如[target doSomething];会被转化成objc)msgSend(target,@select ...

  5. Effective Objective-C 2.0 学习记录

    由于最近入职,公司安排自由学习,于是有时间将Effective Objective-C 2.0一书学习了一遍.由于个人知识面较窄,对于书中有些内容无法理解透彻,现将所学所理解内容做一遍梳理,将个人认为 ...

  6. oc - runtime运行机制

      Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时做的事放到了运行时来处理.同时OC也是一门简单的语言,很大一部分是C的内容,只是在语言层面上加了关键字和语法,真正让OC强大 ...

  7. Objective-C总Runtime的那点事儿(一)消息机制【转】

    RunTime简称运行时.就是系统在运行的时候的一些机制,其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 ).编译完成之后直接顺序执行,无任何 ...

  8. iOS开发:详解Objective-C runTime

    Objective-C总Runtime的那点事儿(一)消息机制 最近在找工作,Objective-C中的Runtime是经常被问到的一个问题,几乎是面试大公司必问的一个问题.当然还有一些其他问题也几乎 ...

  9. runtime--小白看过来

    目录 RunTime 概述 RunTime消息机制 RunTime交换方法 RunTime消息转发 RunTime关联对象 RunTime实现字典与模型互转 1.RunTime 概述 我们在面试的时候 ...

随机推荐

  1. (转) vector的reserve和resize

    文章转自  http://www.cnblogs.com/qlee/archive/2011/05/16/2048026.html vector 的reserve增加了vector的capacity, ...

  2. Android ContentProvider 简单学习

    当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据.以前我们学习过文件的操作模式,通过指定文件的操作模式为Context.MODE_WORL ...

  3. Oracle的表空间和数据文件

    一. 概念 表空间:是一个或多个数据文件的逻辑集合 表空间逻辑存储对象: 永久段-->如表与索引 临时段-->如临时表数据与排序段 回滚段-->用于事物回滚或闪回内存的撤销数据 表空 ...

  4. STM32学习笔记(六) SysTick系统时钟滴答实验(stm32中断入门)

    系统时钟滴答实验很不难,我就在面简单说下,但其中涉及到了STM32最复杂也是以后用途最广的外设-NVIC,如果说RCC是实时性所必须考虑的部分,那么NVIC就是stm32功能性实现的基础,NVIC的难 ...

  5. iOS开发 ReactiveCocoa入门教程 第一部分

    作为一个iOS开发者,你写的每一行代码几乎都是在响应某个事件,例如按钮的点击,收到网络消息,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation).但是这些事件都用不同的方式来处理 ...

  6. CPU的高速缓存存储器知识整理

    基于缓存的存储器层次结构 基于缓存的存储器层次结构行之有效,是因为较慢的存储设备比较快的存储设备更便宜,还因为程序往往展示局部性: 时间局部性:被引用过一次的存储器的位置很可能在不远的将来被再次引用. ...

  7. Sql Server 删除所有表

    如果由于外键约束删除table失败,则先删除所有约束: --/第1步**********删除所有表的外键约束*************************/ DECLARE c1 cursor f ...

  8. js调用父窗口中的方法

    window.open调用父窗口中的方法 回调函数: function fun9(ex){ alert(ex); } 调用语句: window.open("RoomSelecter.htm? ...

  9. 使用jQuery Mobile的注意事项(译)

    翻译编辑自:http://www.appnovation.com/blog/7-things-know-about-jquery-mobile-working-it 一.Android和IOS的内置键 ...

  10. Windows Store App 全球化:在XAML元素中引用字符串资源

    在应用程序中可以通过XAML元素和后台代码两种方式引用资源文件中的字符串资源.本小节先讲述如何在XAML元素中引用字符串资源的相关知识点. 在XAML元素中可以通过使用x:Uid属性来引用资源文件中的 ...