热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ObjectiveCRuntime(一):类与对象

Objective-CRuntime(一):类与对象Runtime介绍Objective-C语言是一门动态语言,它将很多静态

Objective-C Runtime (一):类与对象

Runtime介绍

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这意味着它不仅需要一个编译器,也需要一个运行时系统来动态得创建类和对象、进行消息传递和转发。这个运行时系统即Objc Runtime。Objc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。

Runtime库主要做下面几件事:

  1. 封装:在这个库中,对象可以用C语言中的结构体表示,而方法可以用C函数 来实现,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法了。
  2. 消息传递:当程序执行[object doSomething]时,会向消息接收者(object)发送一条消息(doSomething),runtime会根据消息接收者是否能响应该消息而做出不同的反应。这将在后面详细介绍。

在接下来的一系列文章中,我将介绍一下runtime的基本工作原理以及在我们的代码里可以用它来做什么。在本文中,我们先来了解一下类与对象。

类与对象基础数据结构

###OC对象 OC的对象主要可以分为三种:

  1. instance对象(实例对象)
  2. class对象(类对象)
  3. meta-class对象(元类对象):主要存储着isa指针,superclass指针,类的类方法的信息(class method)。

instance对象 它主要是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象。

NSObjcet *object1 = [[NSObjcet alloc] init];

instance对象在内存中存储的信息包括:

  1. isa指针
  2. 成员变量

class对象 我们通过class方法或runtime方法得到一个class对象。class对象也就是类对象。==每一个类在内存中有且只有一个class对象==。

Class objectClass1 = [NSObject class];
// runtime
Class objectClass2 = object_getClass(object1);

class对象在内存中存储的信息主要包括:

  1. isa指针
  2. superclass指针
  3. 类的属性信息(@property)
  4. 类的成员变量信息(ivar)
  5. 类的对象方法信息(instance method)
  6. 类的协议信息(protocol)

meta-class对象 我们通过runtime方法得到一个class对象。==每个类在内存中有且只有一个meta-class对象。==

//runtime中传入类对象此时得到的就是元类对象
Class objectMetaClass = object_getClass([NSObject class]);
// 判断该对象是否为元类对象
class_isMetaClass(objectMetaClass)

meta-class对象在内存中存储的信息主要包括:

  1. isa指针
  2. superclass指针
  3. 类的类方法的信息(class method)

我们来看看下面的图,来分析这三者的关系

从上图中,我们可以分析出:

  1. instance对象的isa指向class
  2. class的isa指向meta-class
  3. meta-class的isa指向基类的meta-class,基类的isa指向自己
  4. class的superclass指向父类的class,如果没有父类,superclass指针为nil
  5. meta-class的superclass指向父类的meta-class,基类的meta-class的superclass指向基类的class
  6. instance对象调用对象方法的轨迹,isa找到class,方法不存在,就通过superclass找父类
  7. class调用类方法的轨迹,isa找meta-class,方法不存在,就通过superclass找父类

###Class

Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。在objc/objc.h它的定义如下:

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

objc/runtime.h中我们可以看到结构体objc_class的定义如下:

struct objc_class {Class _Nonnull isa OBJC_ISA_AVAILABILITY;#if !__OBJC2__Class _Nullable super_class OBJC2_UNAVAILABLE;// 父类const char * _Nonnull name OBJC2_UNAVAILABLE;// 类名long version OBJC2_UNAVAILABLE;// 类的版本信息,默认为0long info OBJC2_UNAVAILABLE;// 类信息,供运行期使用的一些位标识long instance_size OBJC2_UNAVAILABLE;// 该类的实例变量大小struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;//该类的成员变量链表struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;// 方法定义的链表struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;// 方法缓存struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;// 协议链表
#endif} OBJC2_UNAVAILABLE;

###1. name 类名

// 获取类的类名
const char * class_getName ( Class cls );

###2. isa 在Objective-C中,类自身也是一个对象,我们称之为类对象,在这个类对象中,也有一个isa指针,它指向了metaClass(元类)

###3. super_class 指向该类的父类,如果该类已经是最顶层的根类(如NSObject或NSProxy),则super_class为nil。

###4. instance_size

// 获取实例大小
size_t class_getInstanceSize ( Class cls );

###5. objc_ivar_list 成员变量和属性信息。ivars是一个数组,所有的成员变量、属性的信息是放在链表ivars中的。

######获取成员变量信息

// 获取整个成员变量列表
Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
//获取一个成员变量的名字
const char * _Nullable ivar_getName(Ivar _Nonnull v)
//获取一个成员变量的
const char * _Nullable ivar_getTypeEncoding(Ivar _Nonnull v)

  • ivar_getTypeEncoding函数获取的是变量的数据类型,详细的说明可以看苹果官方文档Type Encodings
  • class_copyIvarList函数,它返回一个指向成员变量信息的数组。这个数组不包含在父类中声明的变量。outCount指针返回数组的大小。需要注意的是,我们必须使用free()来释放这个数组。

######获取成员变量属性信息

/// An opaque type that represents an Objective-C declared property.
typedef struct objc_property *objc_property_t;
//获取整个成员变量属性列表
objc_property_t _Nonnull *_Nullable class_copyPropertyList(Class _Nullable cls, unsigned int * _Nullable outCount)/// Defines a property attribute
typedef struct {const char * _Nonnull name; /**} objc_property_attribute_t;objc_property_attribute_t * _Nullable property_copyAttributeList(objc_property_t _Nonnull property,unsigned int * _Nullable outCount)

  • objc_property_attribute_t其实是对属性的详细描述,包括属性名称、属性编码类型、原子类型/非原子类型等。如T@"NSString",C,N,V_title,TQ,N,V_age

下面详细地说明property_getAttributes获取到的属性的语义:

  • 第一:T总是第一个,它代表类型。 对于类类型,它都是T@类型,其中@表示对象类型;对于id类型,它就是@;而对于基本数据类型,它都是T加上编码类型(@encode(type)),比如int类型就是Ti。
  • 第二:表示属性编码类型,比如是C表示copy,&表示strong,W表示weak等。若是基本类型,它默认是assign,因此此时它是空的。
  • 第三:指定是nonatomic还是atomic,若是nonatomic,则用N表示,若是atomic,则值为空。比如的count属性的详细描述为:Ti,N,V_count,它表示int类型、nonatomic、成员变量名为_count;tomicProperty属性描述为:T@NSNumber,&,V_atomicProperty,它表示类型为NSNumber且为对象类型、strong、atomic、成员变量名为_atomicProperty。
  • 第四:在详细描述中,属性名称是V开头,后面跟着成员变量名称。

属性的详细说明Property Type

###6. methodLists 对象方法列表。

/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method;struct objc_method {SEL method_name; // 方法名称char *method_typesE; // 参数和返回类型的描述字串IMP method_imp; // 方法的具体的实现的指针
}

获取method信息:

//方法列表
Method _Nonnull * _Nullable class_copyMethodList(Class _Nullable cls, unsigned int * _Nullable outCount)
//方法名
SEL _Nonnull method_getName(Method _Nonnull m)
//方法实现
IMP _Nonnull method_getImplementation(Method _Nonnull m)
//方法参数和返回类型的信息
const char * _Nullable method_getTypeEncoding(Method _Nonnull m)
//方法参数数量
unsigned int method_getNumberOfArguments(Method _Nonnull m)
//方法参数类型
char * _Nullable method_copyArgumentType(Method _Nonnull m, unsigned int index)

  • method_getTypeEncoding获取函数的编码,其结果是一串值,如:v16@0:8;@16@0:8;v24@0:8@16。

这些字符串是什么意思,通过苹果官方文档我们可以分析出:

  1. 第一个位置是返回值类型,比如第一个方法返回值是V,第二个的是@,第三个的是v
  2. 第二/三个位置是第一/二个参数,参数列表从左到右算。分别是@ :,@ :,@ :,都是对象,其实第一个和第二个参数是固定的,第一个是接收消息的对象,而第二个是方法选择器SEL。
  3. 如果还有其它参数,依次…
  4. Type Encodings

###7. cache 用于缓存最近使用的方法。一个接收者对象接收到一个消息时,它会根据isa指针去查找能够响应这个消息的对象。在实际使用中,这个对象只有一部分方法是常用的,很多方法其实很少用或者根本用不上。这种情况下,如果每次消息来时,我们都是methodLists中遍历一遍,性能势必很差。这时,cache就派上用场了。在我们每次调用过一个方法后,这个方法就会被缓存到cache列表中,下次调用的时候runtime就会优先去cache中查找,如果cache没有,才去methodLists中查找方法。这样,对于那些经常用到的方法的调用,但提高了调用的效率。

参考:

  1. tech.yunyingxbs.com/article/det…
  2. developer.apple.com/library/con…



推荐阅读
  • 本文介绍了在处理不规则数据时如何使用Python自动提取文本中的时间日期,包括使用dateutil.parser模块统一日期字符串格式和使用datefinder模块提取日期。同时,还介绍了一段使用正则表达式的代码,可以支持中文日期和一些特殊的时间识别,例如'2012年12月12日'、'3小时前'、'在2012/12/13哈哈'等。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • Iamtryingtocreateanarrayofstructinstanceslikethis:我试图创建一个这样的struct实例数组:letinstallers: ... [详细]
  • php缓存ri,浅析ThinkPHP缓存之快速缓存(F方法)和动态缓存(S方法)(日常整理)
    thinkPHP的F方法只能用于缓存简单数据类型,不支持有效期和缓存对象。S()缓存方法支持有效期,又称动态缓存方法。本文是小编日常整理有关thinkp ... [详细]
  • 标题: ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • 本文分析了Wince程序内存和存储内存的分布及作用。Wince内存包括系统内存、对象存储和程序内存,其中系统内存占用了一部分SDRAM,而剩下的30M为程序内存和存储内存。对象存储是嵌入式wince操作系统中的一个新概念,常用于消费电子设备中。此外,文章还介绍了主电源和后备电池在操作系统中的作用。 ... [详细]
  • Netty源代码分析服务器端启动ServerBootstrap初始化
    本文主要分析了Netty源代码中服务器端启动的过程,包括ServerBootstrap的初始化和相关参数的设置。通过分析NioEventLoopGroup、NioServerSocketChannel、ChannelOption.SO_BACKLOG等关键组件和选项的作用,深入理解Netty服务器端的启动过程。同时,还介绍了LoggingHandler的作用和使用方法,帮助读者更好地理解Netty源代码。 ... [详细]
  • 用Vue实现的Demo商品管理效果图及实现代码
    本文介绍了一个使用Vue实现的Demo商品管理的效果图及实现代码。 ... [详细]
  • 基于分布式锁的防止重复请求解决方案
    一、前言关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查 ... [详细]
  • 初识java关于JDK、JRE、JVM 了解一下 ... [详细]
author-avatar
Min2502857657_377
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有