Object-C(以后简称OC)中有id类型,相对于明确定义类型的静态类型,称为动态类型。

使用动态类型,配合多态(不同类型拥有同名方法),动态绑定(运行时决定实际调用的方法)可以将很多判断延迟到运行时决定,比如运行时才决定对象是某个类型,决定调用哪个类型的方法等。这样提高了灵活性,但是同样带来了风险,所以和支持动态类型的其他面向对象的语言一样,需要提供机制来做运行时判断,这样可以一定程度规避运行时错误。

看到一个动态类型的实例对象,我们都会习惯提出的问题:

1. 这个对象是属于某个类么?或者这个对象的类型是什么?

2. 这个对象支持接收某个消息么?或者说这个对象的类型定义了某个方法么?

等等...

要了解这些问题的答案,我们看看头文件NSObject.h中的protocol定义中的一些代码片段:

@protocol NSObject 

- (Class)superclass;

- (Class)class;

- (id)self; 

- (id)performSelector:(SEL)aSelector;

- (id)performSelector:(SEL)aSelector withObject:(id)object;

- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

- (BOOL)isKindOfClass:(Class)aClass;

- (BOOL)isMemberOfClass:(Class)aClass;

- (BOOL)respondsToSelector:(SEL)aSelector; 

@end

现在我们都看到了减号‘-’,就是说这些都是实例对象可以发送的消息,我们挨个过一遍:

- (Class)superclass;

Class是一个指针结构定义,OC系统会从该指针中获得类型信息,比如你写如下代码:

NSString * obj = @"nsstring";

Class objClass = [obj class];

id objClass1 = [obj class];

调试一下,你会看到objClass的值是(class)_NSCFConstantString,而objClass1的值是一个指针值,类似(id)0x7fff779d73b8(这是一个在64位上执行的结果),objClass的值是OC系统从objClass1的指针值中获取的,因为OC系统会跟踪每个实例对象所属类型的对应关系。

所以你可以用类似于下面的代码来判断两个对象实例的父类型是否一致:

if ([obj1 supperclass] == [obj2 supperclass]) {//do sth...}

- (Class) class同理,用于获取实例对象的类型信息。

- (id) self,用于获取本身实例的指针值。

讲selector前,我们先看看下面两个消息定义:

- (BOOL)isKindOfClass:(Class)aClass
- (BOOL)isMemberOfClass:(Class)aClass;

IsKindOfClass顾名思义,是说对象的类型是否是某个类型,那么下面的代码中的两个布尔值都应该是YES。

NSString * str = "nsstring";

Class strClass = [str class];

Class strSuperClass = [str superclass];

BOOL isNSString = [str isKindOfClass: strClass];

BOOL isNSObject = [str isKindOfClass: strSuperClass];]

IsMemberOfClass,从字面意思看,貌似是问对象是不是某个类型的成员?有些别扭 :(,我们来看看代码执行结果来判断实际用途:

NSString * str = "nsstring";

Class strClass = [str class];

Class strSuperClass = [str superclass];

BOOL isNSStringMember = [str isMemberOfClass: strClass];

BOOL isNSObjectMember = [str isMemberOfClass: strSuperClass];]

执行结果是:isNSStringMember为YES,isNSObjectMember为NO。所以看起来isMemberOfClass用来鉴别对象是不是直接的某类型的实例,而不是继承关系的实例。

所以个人认为,这两个方法名字应该改动如下:

isKindOfClass -> isInstanceOfClass

isMemberOfClass -> isDirectInstanceOfClass

当然,源代码定义接口名称时候,应该是有所考虑的,暂且认为自己没有理解原作者的用意吧。

下面我们看跟4个selector相关的方法定义:

- (BOOL)respondsToSelector:(SEL)aSelector; 

这个方法名称很明确,判断某个对象是否响应指定的selector,这里我们看看看SEL类型的selector是什么?在objc.h中有如下定义:

typedef struct objc_selector *SEL;

和Class类似是一个结构指针,该结构是OC系统用来保存方法定义信息的,OC系统通过该指针可以查询到方法的签名信息和类属信息。OC中提供了关键之@selector来获取一个方法的SEL指针值。那么下面代码中isOK是YES,因为NSString是NSObject,所以必须能够响应init方法。

NSString * str = @"nsstring";

BOOL isOK = [str respondsToSelector: @selector (init)];

- (id)performSelector:(SEL)aSelector;

performSelector有三个变体,第一个是没有参数的,看看下面的代码:

NSString * str = @"nsstring";

SEL message = @selector(hash);

id var = [str performSelector: message];

id var1 = [str hash];

NSString对象是NSObject对象,因此肯定可以执行hash方法,那么var和var1的值必须是相等的,因为对于同一个对象取哈西值多次,每次值都应该是一样的。

另外两个performSelector同理,只是适应于方法签名有一个参数和有两个参数的情况。假设add方法定义如下:

- (id) add: (id) number;

那么SEL应该是像下面这样获取的:

SEL addMessage = @selector(add:);

id var = [number1 performSelector:add withObject:number];

打完收工,OC的方块发送消息的方式写着写着就慢慢习惯了~~

Object-C中动态类型对象相关操作汇总的更多相关文章

  1. Javascript学习1 - Javascript中的类型对象

    原文:Javascript学习1 - Javascript中的类型对象 1.1关于Numbers对象. 常用的方法:number.toString() 不用具体介绍,把数字转换为字符串,相应的还有一个 ...

  2. grails项目中(DB的相关操作)

    grails项目中(DB的相关操作) save:保存Domain对象的数据到对应的库表中(可能是insert也可能是update) findBy: 动态方法,查找并返回第一条记录,方法名可以变化 eg ...

  3. C++中的类型判断typeid()操作与java中的 instanceof 做比较

    这是RTTI(运行阶段类型识别)的问题,c++有三个支持RTTI的元素: 1. dynamic_cast 操作符     如果可能的话,dynamic_cast操作符将使用一个指向基类的指针来生成一个 ...

  4. mysql 5.7 laravel json类型数据相关操作

    2018年10月16日18:14:21 官方文档中文翻译版 原文:https://dev.mysql.com/doc/refman/5.7/en/json.html 最后有部分实例和一个小总结 11. ...

  5. .NET中的类型对象

    .NET中的任何类型,都有对应的一个类型对象.类型对象和类型实例(类型创建的一个对象)不是同一个概念. 类型对象包含类型的静态字段和方法,当类访问静态方法静态字段,实例调用方法时就会去类型对象中查找静 ...

  6. Redis中String类型的相关命令操作

    String append 如果key已存在,则直接在value追加值,如果key不存在,则会插件一个新的value为空的key,然后在追加 127.0.0.1:6379> set name l ...

  7. JavaScript中的DOM及相关操作

    一.什么是DOM JavaScript由ECMAScript.DOM和BOM三部分组成,其中DOM代表描述网页内容的方法和接口,即文档对象模型(Document Object Model).在网页上, ...

  8. 关于Emit中动态类型TypeBuilder创建类标记的一点思考

      利用TypeBuilder是可以动态创建一个类型,现在有个需求,动态生成一个dll,创建类型EmployeeEx,需要继承原dll里面的Employee类,并包含Employee类上的所有类标记. ...

  9. js中闭包和对象相关知识点

    学习js时候,读到几篇不错的博客.http://www.cnblogs.com/yexiaochai/p/3802681.html一,作用域 和C.C++.Java 等常见语言不同,JavaScrip ...

随机推荐

  1. 在table中进行内容搜索

    $("tbody td").filter(":contains('" + x + "')").css('color','red').pare ...

  2. 用Redis构建分布式锁-RedLock(真分布)

    在不同进程需要互斥地访问共享资源时,分布式锁是一种非常有用的技术手段. 有很多三方库和文章描述如何用Redis实现一个分布式锁管理器,但是这些库实现的方式差别很大,而且很多简单的实现其实只需采用稍微增 ...

  3. 用shell在一个文件后面的每一行追加数据

    在shell分析log的时候,需要将数据过滤后转为csv的格式: 要在分析好的数据后面追加逗号: sed 's/$/&,/g' no2.log > ccc.log 结果保存在ccc.lo ...

  4. mysql 行转列 和 列转行

    我们有时会将一些数据已逗号的连接方式存在数据库,当取出时我们又想单独一个个取出来 利用help_topic 的自增性 LENGTH(wu.`password`) - length(replace(wu ...

  5. Android之ProgressBar

    今天复习一下以前的知识,补充一下ProgressBar控件 progressBar是进度条组件,通常用于用户展示某个耗时操作完成的进度,而不让用户感觉是程序失去了响应,从而更好地提升用户界面的友好性. ...

  6. VLC嵌入网页,终于要成功了!

    <OBJECT classid="clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921" width="640" heig ...

  7. alphaBlend

    // Alpha = srcAlpha + dstAlpha - srcAlpha * dstAlpha / 0xFF;// R = (srcR * srcAlpha + dstR * dstAlph ...

  8. Finders Keepers

    function find(arr, func) { //var num = 0; //return num; var res = arr.filter(func); if(res.length){ ...

  9. 记一次TFS 的 垃圾提示(无法下载 未获取项目 的 代码)

    提示 “ 所有文件都是最新的 ”,但是在 源码管理 里面 确是 “未下载” 我艹,第一次遇到.如图.~~ 最后发现是 TFS 的项目权限设置问题. 你妈个马批的,啥子鸡巴破B提示,太阳你妈B 的 .要 ...

  10. Smali语法编程

    Smali背景: Smali,Baksmali分别是指安卓系统里的Java虚拟机(Dalvik)所使用的一种.dex格式文件的汇编器,反汇编器.其语法是一种宽松式的Jasmin/dedexer语法,而 ...