运行时-二

原创 2015年11月18日 22:29:18

从一道面试题说开去

有一个Person类继承于NSObject,它有一个子类Student。
现在在Student里写下如下代码,求输出结果

Student *stu = [[Student alloc] init];
NSLog(@"%@ %@ %@ %@",[self class],[super class],[self superClass],[super superClass]);

class

  • class方法的作用:返回【方法调用者】的类型 比如[UITableViewCell class]
  • superClass方法的作用:返回【方法调用者】的父类类型,
  • super的含义:子类可以借助super关键字去调用父类的方法 比如if (self = [super init]).所以[super class]意思是self借助它父类的class方法,调用者依然是self,返回的是子类
  • self的含义:方法调用者.
  • 所以无论self还是super调用,方法调用者都是self

运行时

  • 用终端来到文件夹,里面有个OC文件比如main.m,输入clang -rewrite-objc main.m,可以重写成C++语言代码,有十万多行,因为要支撑起整个项目确实要这么多,即使它只有一个main

  • 官方文档的介绍:

In Objective-C, messages aren’t bound to method implementations until runtime. The compiler converts a message expression,

[receiver message]
into a call on a messaging function, objc_msgSend. This function takes the receiver and the name of the method mentioned in the message—that is, the method selector—as its two principal parameters:

objc_msgSend(receiver, selector)
  • 所有方法都是转成发消息,比如上面一行代码,receiver调用message方法,会转换成给receiver发送消息”message”
  • 我们在写OC程序的时候用的都是运行时方法
  • 可以通过运行时来查看我们代码的C语言底层实现。这里以[super description]为例详细解释
  • 在main程序里写如下代码,目的是研究super到底是怎么实现的
@interface Person : NSObject

@end

@implementation Person

- (NSString *)description{
    return [super description];
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {

    }
    return 0;
}
  • 然后按照上面的方法转成C++代码,搜索”description” (小细节:消息都是带双引号的,带上双引号能缩小范围),得到如下代码A
return ((NSString *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Person"))}, sel_registerName("description"));
  • 上面官方文档可知:给谁发消息,谁就是消息接受者receiver,谁就是方法调用者,因此只要看是给谁发消息就知道是谁调用了方法
  • 很多小括号是类型强转,可以去掉,而大括号是个结构体,比如
struct Date{
    int year;
    int month;
}
struct Date d = {2015,10};
  • 把结构体换成一个参数,剩下的也是一个参数,再把强转的小括号去掉,就简化成如下
id temp1 = {self, class_getSuperclass(objc_getClass("Person"))};
id temp2 = sel_registerName("description")
return objc_msgSendSuper(temp1, temp2);
  • 代码A其实就是[super description]的底层实现。现在能看懂了,super关键字调用的是objc_msgSendSuper函数,而一般调用objc_msgSend这个函数(与super比较很简单,略过不表,我们说super)。而它的第一个参数temp1就是方法调用者receiver,第二个参数是方法description
  • 点击objc_msgSendSuper这个方法进去看一下说明,它的两个参数是struct objc_super *super和SEL op
  • 重点是第一个参数(对应为temp1),再点进去看说明,是下面这些
struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained Class class;
#else
    __unsafe_unretained Class super_class;
#endif
    /* super_class is the first class to search */
};
  • 这个结构体乍看有三个参数,实际上是两个:后面那个是二选一(如果不是C++并且不是ObjC2,选一,否则选二,现在是选二)
__unsafe_unretained id receiver;
__unsafe_unretained Class super_class;
  • 可以看出这个结构体的第一个参数就是receiver,对应的上面的temp1的第一个参数是self,OK,真相大白,消息接受者也就是方法调用者就是self
  • 再看看结构体的第二个参数(id)class_getSuperclass(objc_getClass(“Person”)),class_getSuperclass意思是取得父类,那么这句代码意思就是objc_getClass(“NSObject”)。于是temp1参数现在就是id temp1 = {self,objc_getClass(“NSObject”)}
  • 于是,代码A的意思就是person这个类,去它的父类NSObject找到description方法给自己调用

iOS运行时(runtime)探究二:主要函数

一、类相关操作函数// 获取类的类名 const char * class_getName ( Class cls );// 获取类的父类 Class class_getSuperclass ( Cl...

Android 6.0(API 23) 运行时权限(二)之权限申请

在上一篇中简单介绍了运行时权限,今天就讲讲怎么去申请权限。这个项目中本来用了一个第三方的权限框架,但是不太好用,我就在github上选择了start最多的PermissionsDispatcher 。...

Flume NG源码分析(二)支持运行时动态修改配置的配置模块

在上一篇中讲了Flume NG配置模块基本的接口的类,PropertiesConfigurationProvider提供了基于properties配置文件的静态配置的能力,这篇细说一下PollingP...
  • ITer_ZC
  • ITer_ZC
  • 2015年06月08日 17:08
  • 2184

Android 6.0以上 需要运行时申请的权限(二)

一、 运行时权限分类 Android 6.0 以上的权限变成了运行时权限,在需要使用某个权限的时候必须动态去申请使用,直接访问直接导致app崩溃!权限分为一般权限和危险权限两种,一般权限跟以前一样在...

iOS动态性(二):运行时runtime初探(强制获取并修改私有变量,强制增加及修改私有方法等)

原文网址:http://www.cnblogs.com/wengzilin/p/4344952.html?utm_source=tuicool OC是运行时语言,只有在程序运行时,才...

【android】应用程序安装过程分析(二)——————系统正常运行时的安装过程

转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/19578947 前言 我们知道,在android手机上安装一个apk很...

《深入java虚拟机--JVM高级特性与最佳实践》学习笔记(二) JAVA虚拟机运行时数据区

1. 程序计数器 可看成是当前线程所执行的字节码的行号指示器,通过改变计数器的值来选取下一条要执行的字节码指令,分支、循环、跳转、异常处理、恢复等基础功能都需要依赖这个计数器来完成。线程私有,互不影...

Objective-C Runtime 运行时之二:成员变量与属性

在前面一篇文章中,我们介绍了Runtime中与类和对象相关的内容,从这章开始,我们将讨论类实现细节相关的内容,主要包括类中成员变量,属性,方法,协议与分类的实现。 本章的主要内容将聚集在Runtim...
  • lvwuxue
  • lvwuxue
  • 2016年08月19日 17:42
  • 763

Objective-C Runtime 运行时之二:成员变量与属性

在前面一篇文章中,我们介绍了Runtime中与类和对象相关的内容,从这章开始,我们将讨论类实现细节相关的内容,主要包括类中成员变量,属性,方法,协议与分类的实现。 本章的主要内容将聚集在Runt...
  • wsjshx
  • wsjshx
  • 2015年11月23日 15:40
  • 439

Objective-C Runtime 运行时之二:成员变量与属性

在前面一篇文章中,我们介绍了Runtime中与类和对象相关的内容,从这章开始,我们将讨论类实现细节相关的内容,主要包括类中成员变量,属性,方法,协议与分类的实现。 本章的主要内容将聚集在Runt...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:运行时-二
举报原因:
原因补充:

(最多只允许输入30个字)