赞
踩
Objective-C是基于C语言加入面向对象特性和消息转发机制的动态语言,这就是说它不仅需要一个编译器,还需要Runtime系统动态的创建类和对象,进行消息发送和转发。关于Runtime概念众说纷纭。理解Runtime,我们从源码开始…. 源码介绍 Runtime在实际开发中,其实就是一组C语言函数。
官方介绍:官方文档
The Objective-C language defers as many decisions as it can from compile time and link time to runtime. Whenever possible, it does things dynamically. This means that the language requires not just a compiler, but also a runtime system to execute the compiled code. The runtime system acts as a kind of operating system for the Objective-C language; it’s what makes the language work.
怎么理解这句话呢?尽量将决定放到运行的时候,而不是在编译和链接过程…如图所示
Clang是一个C语言、C++、Objective-C、Objective-C++语言的轻量级编译器。
官方介绍:官方文档
clang is a C, C++, and Objective-C compiler which encompasses preprocessing, parsing, optimization, code generation, assembly, and linking.
源代码:main.m
//
// main.m
// YJDoctor
//
// Created by YJHou on 2015/10/25.
// Copyright © 2015年 houmanager@hotmail.com. All rights reserved.
//
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSObject *obj = [[NSObject alloc] init];
NSLog(@"-->%@", obj);
}
return 0;
}
编译器:
clang -rewrite-objc main.m
生成了mian.cpp文件,打开查看源码:
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_dr_k2drvnh548q5293brg9wmgzc0000gn_T_main_2a142f_mi_0, obj);
}
return 0;
}
似乎看到了Runtime的影子:objc_msgSend、objc_getClass、sel_registerName…
打开资源地址:/usr/include/objc 会发现如下文件:
Runtime 在实际开发中,会经常用到吗?这个答案是肯定的。但是Runtime用的好不好在于理解程度,理解的好代码质量高效实用;用的不好,容易自己造坑。在实际开发中,我并不是推荐大家熟悉灵活的运用底层的东西,而是熟悉知道底层的运行机制。要不已经封装好看又好用的API干啥使。
Runtime 具体都干啥使用?
比如:动态添加属性、动态添加方法、方法交换、字典模型转换
面试经历: 曾经一次面试,面试官说类别能不能设置属性?咋一听,条件反射类别还能设置属性,什么鬼,后来一想面试官问的是怎么给类别添加属性吧,用词准确很重要,添加和设置概念是不同的。面试官马上更正是添加不是设置。
打开runtime.h会看到数据结构如图所示:
Messaging 官方介绍
Dynamic Method Resolution 官方介绍
从有图可以看出,ObjC 类本身同时也是一个对象,为了处理类和对象的关系,runtime 库创建了一种叫做元类 (Meta Class) 的东西,类对象所属类型就叫做元类,它用来表述类对象本身所具备的元数据。类方法就定义于此处,因为这些方法可以理解成类对象的实例方法。
每个类仅有一个类对象,而每个类对象仅有一个与之相关的元类。当你发出一个类似 [NSObject alloc] 的消息时,你事实上是把这个消息发给了一个类对象 (Class Object) ,这个类对象必须是一个元类的实例,而这个元类同时也是一个根元类 (root meta class) 的实例。所有的元类最终都指向根元类为其超类。所有的元类的方法列表都有能够响应消息的类方法。所以当 [NSObject alloc] 这条消息发给类对象的时候,objc_msgSend() 会去它的元类里面去查找能够响应消息的方法,如果找到了,然后对这个类对象执行方法调用。
在Runtime System没有在本类的method_lists没有找到匹配的实现方法时,我们可以动态的添加一个方法,这是开始进行消息转发(messaging forward)前的第一阶段,例如我们用@dynamic关键字在类的实现文件中修饰一个属性:这表明我们会为这个属性动态提供存取方法,编译器不会默认为我们生成setPropertyName:和propertyName方法,而需要我们动态提供。
同样我们可以通过分别重载resolveInstanceMethod:和resolveClassMethod:方法分别添加实例方法实现和类方法实现。因为当 Runtime 系统在Cache和方法分发表中来给程序员一次动态添加方法实现的机会。我们需要用class_addMethod函数完成向特定类添加特定方法实现的操作:
Message Forwarding 官方介绍
消息转发分为两大阶段。
第二阶段涉及“完整的消息转发机制(full forwarding mechanism)”如果运行期系统已经执行完第一阶段,此时,运行期系统会请求我接收者以其它手段来处理消息。可以细分3小步。
1.首先查找有没有replacement receiver进行处理。若无;
2.运行期系统把Selector相关信息封装到NSInvocation对象中;
3.再给一次机会,若依旧未处理则让NSObject调用doNotReconizeSelector:
由此我们可以看到,object_getClass返回的其实是class的metaClass,即Class这个类对象的类,这个概念有点绕。梳理一下:Person这么一个类(0x1000f53c8),它的isa指针指向其元类(地址0x1000f53f0),这个元类的isa指针指向基类NSObject的元类,即根元类(0x1a7919ec8),再递进一层可以发现,根元类的isa指针指向自己,这样就形成了一个完整的闭环。
由此可知objc_getClass方法只是单纯地返回了Class,而非isa指针指向的Class。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。