今天在准备出笔试题的过程中随便搜了一下其他的笔试题,看到其中一个就是关于performSelector与直接调用的区别。

个人感觉这其实是一个陷阱题,因为大部分应用场景下,用哪一种都可以,可以说是没有区别的,但其实又有一些细节上的区别。

比如说,假如有如下代码:

- (void)doTest {

    Student* student = [[Student alloc] init];

    [student performSelector:@selector(doSomething)];

    [student doSomething];

}

具体执行过程中的区别道理是什么呢?

还是先看官方文档对performSelector的描述:

- (id)performSelector:(SEL)aSelector

Description

Sends a specified message to the receiver and returns the result of the message. (required)

The performSelector: method is equivalent to sending an aSelector message directly to the receiver. For example, all three of the following messages do the same thing:

id myClone = [anObject copy];

id myClone = [anObject performSelector:@selector(copy)];

id myClone = [anObject performSelector:sel_getUid("copy")];

However, the performSelector: method allows you to send messages that aren’t determined until runtime。 A variable selector can be passed as the argument:

SEL myMethod = findTheAppropriateSelectorForTheCurrentSituation();

[anObject performSelector:myMethod];

The aSelector argument should identify a method that takes no arguments. For methods that return anything other than an object, use NSInvocation.

核心的就那么几句:

1 执行的效果其实和发送消息是等价的;

2 performSelector允许发送未在运行时确定的消息;也就是说,只要这个消息能够被转发到正确的接收者,能够被最后的接收者识别,都是可以正确运行的。否则,就会在运行时报错“unrecognized selector sent to instance”.

具体来说:假如上面的Student的定义和实现如下:

@interface Student : NSObject

- (void)doSomething;

@end

@implementation Student

- (void)doSomething {

    NSLog(@"doSomething");

}

@end

那么这两者基本上是等价的;但是,假如doSomething是一个私有的方法呢? 可以试着将这个方法从头文件中删除如下:

@interface Student : NSObject

@end

这个时候[student doSomething];就会在编译时候报错啦!

而对于performSelector呢,仅仅当编译警告选项“Undeclared Selector”打开的时候才会有编译警告。

另外,即使这个方法并没有实现,也就是说从.m文件中删除这个方法,编译是可以通过的,但是运行时会Crash,报的错误就是刚才的“unrecognized selector sent to instance”.

我自己由于是从C++程序员转过来的,所以其实更喜欢[student doSomething]这种方法,一旦有问题的时候,在编译期间就很容易发现啦!

但Obejct-C的动态特性是允许在运行时向某个类添加方法的,这个时候就一定需要使用performSelector了。那么为了避免运行时出现错误,在使用performSelector之前一定要使用如下的检查方法来进行判断。

- (BOOL)respondsToSelector:(SEL)aSelector;

The End.

performSelector调用和直接调用的区别的更多相关文章

  1. oracle创建函数和调用存储过程和调用函数的例子(区别)

    创建函数: 格式:create or replace function func(参数 参数类型) Return number Is Begin --------业务逻辑--------- End; ...

  2. 调用run与调用start的区别

    调用start的结果 package TestException; public class test1 { public static void main(String[] args) { // 3 ...

  3. MFC OnPaint()函数中最先调用CDialog::OnPaint()和最后调用CDialog::OnPaint()的巨大区别

    OnPaint()函数中最先调用CDialog::OnPaint()和最后调用CDialog::OnPaint()的巨大区别,如果没有注意这个问题就会出现无厘头式的绘图问题-- 效果就是出不来!在经过 ...

  4. 转 - RPC调用和HTTP调用的区别

    很长时间以来都没有怎么好好搞清楚RPC(即Remote Procedure Call,远程过程调用)和HTTP调用的区别,不都是写一个服务然后在客户端调用么?这里请允许我迷之一笑~Naive!本文简单 ...

  5. RPC调用和HTTP调用的区别

    很长时间以来都没有怎么好好搞清楚RPC(即Remote Procedure Call,远程过程调用)和HTTP调用的区别,不都是写一个服务然后在客户端调用么?这里请允许我迷之一笑~Naive!本文简单 ...

  6. 反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性、字段),而不去使用Invoke方法)

    反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性.字段),而不去使用Invoke方法)   创建Delegate (1).Delegate.CreateDelegate(Type, ...

  7. C#“同步调用”、“异步调用”、“异步回调”

    本文将主要通过“同步调用”.“异步调用”.“异步回调”三个示例来讲解在用委托执行同一个“加法类”的时候的的区别和利弊. 首先,通过代码定义一个委托和下面三个示例将要调用的方法: ); //模拟该方法运 ...

  8. C++调用DLL有两种方法——静态调用和动态调用

    C++调用DLL有两种方法——静态调用和动态调用 标签: dllc++winapinullc 2011-09-09 09:49 11609人阅读 评论(0) 收藏 举报  分类: cpp(30)  [ ...

  9. dll静态调用和动态调用

    动态链接库有2种连接方式,一种是通过库直接加入(又叫隐式加载或载入时加载),一种是在运行时加入.后者很好理解,比如LoadLibrary(),GetProcAddress()获取想要引入的函数,使用完 ...

  10. C#(同步调用、异步调用、异步回调)

    Review: 原作者虽然使用了汉字的类名,看起来十分蹩脚,但是,还是把同步调用.异步调用.异步回调的使用讲解的很详细的.原理讲解的很清晰. ------ 本文将主要通过“同步调用”.“异步调用”.“ ...

随机推荐

  1. 「 Luogu P2574 」 XOR的艺术——线段树

    # 解题思路 这题不难,但是原谅我一开始的傻逼想法,一会儿再给大家透露透露. 先说怎么做这题. 显然对于 $0$ 和 $1$ 来说,异或无非也就只有两种变化 异或了奇数次,$0$ 就会变成 $1$,$ ...

  2. SCOI2013 数数

    题目描述 题解: 很玄学的一道数位$dp$,看了很多篇题解才懂. 直接挂$l$的题解. 代码: #include<cstdio> #include<cstring> #incl ...

  3. 【开发工具安装配置】MyEclipse,Tomcat,Mysql安装配置

    配置步骤 注:以下路径仅供参考! 一.MyEclipse10 1. 1 破解版破解说明: (1)下载安装好Myeclipse,先不要运行. (2)打开破解工具目录下的cracker.jar文件或run ...

  4. LINUX常用文件说明

    一.网络配置 1.修改主机名 /etc/sysconfig/network或/etc/hosts 2.开启或关闭网卡 ifconfig eth0 down/up 3.linuxa下查看一个网卡绑定的所 ...

  5. java基础之switch

    switch 语句由一个控制表达式和多个case标签组成. switch 控制表达式支持的类型有byte.short.char.int.enum(Java 5).String(Java 7). swi ...

  6. java环境配置——jdk8

    在官网下载最新版本的jdk 测试版本:jdk-8u60-windows-x64.exe 测试环境:Windows Server 2012 R2 Standard  X64 开始执行安装 安装过程中会选 ...

  7. .NET Core使用log4Net记录日志

    1.引入Nuget包 log4net 2.添加log4Net配置文件 <?xml version="1.0" encoding="utf-8" ?> ...

  8. Python+selenium(定位一组元素)

    我们熟知Webdriver有8种定位元素的方法,但是当需要定位一组元素的时候,可以使用Webdriver提供的与之对应的8种用于定位一组元素的方法,分别是: find_elements_by_id() ...

  9. POJ3246-Balanced Lineup,好经典的题,做法和HDU-I hate it 一样~~

    Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K   Case Time Limit: 2000MS Description For ...

  10. 『NYIST』第八届河南省ACM竞赛训练赛[正式赛一]-CodeForces 236A,虽然很水,但有一个很简单的函数用起来方便

    A. Boy or Girl time limit per test 1 second memory limit per test 256 megabytes input standard input ...