`
java-mans
  • 浏览: 11421600 次
文章分类
社区版块
存档分类
最新评论

Runtime of Objective-C

 
阅读更多

[0] Outline

-- [1] 版本和平台

-- [2] 与Runtime System交互

-- [3] 方法的动态决议

-- [4]消息转发

-- [5]类型编码

-- [6]属性声明


[1] 版本和平台

Runtime System对于Objective-C来说就好比是它的操作系统,或者说是运行的支撑平台,它使得Objective-C代码能够按照既定的语言特性跑起来。相对于C/C++来说,Objective-C尽可能地把一些动作推迟到运行时来执行,即尽可能动态地做事情。因此,它不仅需要一个编译器,还需要一个运行时环境来执行编译后的代码。

Runtime System分为Legacy和Modern两个版本,一般来说,我们现在用的都是Modern版本。Modern版本的Runtime System有一个显著的特征就是“non-fragile”,即父类的成员变量的布局发生改变时,子类不需要重新编译。此外,还支持为声明的属性进行合成操作(即@property@synthesis)。

下面会讨论NSObject类Objective-C程序如何与Runtime System交互运行时动态地加载类发消息给其它对象,以及运行时如何获取对象信息


[2] 与Runtime System交互

Objective-C程序和Runtime System在三个不同层次进行交互:通过Objective-C源码;通过NSObject定义的函数;以及通过直接调用runtime functions


通常来讲,Runtime System都是在幕后工作,我们需要做的就是编写Objective-C代码,然后编译。编译器会为我们创建相应的数据结构和函数调用来实现语言的动态特性。这些数据结构保存着在类、Category定义和Protocol声明中所能找到的信息,包括成员变量模板、selectors,以及其它从源码中提取到的信息。

Runtime System是一个动态共享库,位于/usr/include/objc,拥有一套公共的接口,由一系列函数和数据结构组成。开发人员可以使用纯C调用一些函数来做编译器做的事情,或者扩展Runtime System,为开发环境制作一些工具等等。尽管一般情况下,编写Objective-C并不需要了解这些内容,但有时候会很有用。所有的函数都在Objective-C Runtime Reference有文档化信息。


Cocoa中大部分对象都是NSObject的子类(NSProxy是一个例外),继承了NSObject的方法。因此在这个继承体系中,子类可以根据需求重新实现NSObject定义的一些函数,实现多态和动态性,比如description方法(返回描述自身的字符串,类似Python中开头的三引号)。

一些NSObject定义的方法只是简单地询问Runtime System获得信息,使得对象可以进行自省(introspection),比如用来确定类类型的isKindOfClass:,确定对象在继承体系中的位置的isMemberOfClass:,判断一个对象是否能接收某个特定消息的respondsToSelector:,判断一个对象是否遵循某个协议的conformsToProtocol:,以及提供方法实现地址的methodForSelector:。这些方法让一个对象可以进行自省(introspect about itself)。


最主要的Runtime函数是用来发送消息的,它由源码中的消息表达式激发。发送消息是Objective-C程序中最经常出现的表达式,而该表达式最终会被转换成objc_msgSend函数调用。比如一个消息表达式[receiver message]会被转换成objc_msgSend(receiver, selector),如果有参数则为objc_msgSend(receiver, selector, arg1, arg2, …)

消息只有到运行时才会和函数实现绑定起来:首先objc_msgSend在receiver中查找selector对应的函数实现;然后调用函数过程,将receiving object(即this指针)和参数传递过去;最后,返回函数的返回值。

发送消息的关键是编译器为类和对象创建的结构,包含两个主要元素,一个是指向superclass的指针,另一个是类的dispatch table,该dispatch table中的表项将selector和对应的函数入口地址关联起来。

当一个对象被创建时,内存布局中的第一个元素是指向类结构的指针,isa。通过isa指针,一个对象可以访问它的类结构,进而访问继承的类结构。示例图可参见此处

当向一个对象发送消息时,objc_msgSend先通过isa指针在类的dispatch table中查找对应selector的函数入口地址,如果没有找到,则沿着class hierarchy(类的继承体系)寻找,直到NSObject类。这就是在运行时选择函数实现,用OOP的行话来说,就是动态绑定。

为了加速发送消息的速度,Runtime System为每个类创建了一个cache,用来缓存selector和对应函数入口地址的映射。


当objc_msgSend找到对应的函数实现时,它除了传递函数参数,还传递了两个隐藏参数:receiving objectselector。之所以称之为隐藏参数,是因为这两个参数在源代码中没有显示声明,但还是可以通过self和_cmd来访问。

当一个消息要被发送给某个对象很多次的时候,可以直接使用methodForSelector:来进行优化,比如下述代码:

//////////////////////////////////////////////////////////////
void (*setter)(id, SEL, BOOL);
int i;

setter = (void (*)(id, SEL, BOOL))[target
     methodForSelector:@selector(setFilled:)];
for ( i = 0; i < 1000, i++ ) 
     setter(targetList[i], @selector(setFilled:), YES);
//////////////////////////////////////////////////////////////

其中,methodForSelector:是由Cocoa Runtime System提供的,而不是Objective-C本身的语言特性。这里需要注意转换过程中函数类型的正确性,包括返回值和参数,而且这里的前两个参数需要显示声明为id和SEL。


[3] 方法的动态决议

有时候我们想要为一个方法动态地提供实现,比如Objective-C的@dynamic指示符,它告诉编译器与属性对应的方法是动态提供的。我们可以利用resolveInstanceMethod:resolveClassMethod:分别为对象方法和类方法提供动态实现。

一个Objective-C方法本质上是一个拥有至少两个参数(self和_cmd)的C函数,我们可以利用class_addMethod向一个类添加一个方法。比如对于下面的函数:

//////////////////////////////////////////////////////////////
void dynamicMethodIMP(id self, SEL _cmd) {
     // implementation ….
}
//////////////////////////////////////////////////////////////

我们可以利用resolveInstanceMethod:将它添加成一个方法(比如叫resolveThisMethodDynamically):

//////////////////////////////////////////////////////////////
@implementation MyClass
+ (BOOL)resolveInstanceMethod:(SEL)aSEL
{
     if (aSEL == @selector(resolveThisMethodDynamically)) {
          class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
          return YES;
     }
     return [super resolveInstanceMethod:aSEL];
}
@end
//////////////////////////////////////////////////////////////

动态决议和发送消息并不冲突,在消息机制起作用之前,一个类是有机会动态决议一个方法的。当respondsToSelector:或者instancesRespondToSelector:被激活时,dynamic method resolver会优先有个机会为这个selector提供一份实现。如果实现了resolveInstanceMethod:,对于不想动态决议而想让其遵循消息转发机制的selectors,返回NO即可。

Objective-C程序可以在运行时链接新的类和category。动态加载可以用来做很多不同的事情,比如System Preferences里头各种模块就是动态加载的。尽管有运行时函数可以动态加载Objective-C模块(objc/objc-load.h中的objc_loadModules),但Cocoa的NSBundle类提供了更方便的动态加载接口。


[4] 消息转发

向一个对象发送它不处理的消息是一个错误,不过在报错之前,Runtime System给了接收对象第二次的机会来处理消息。在这种情况下,Runtime System会向对象发一个消息,forwardInvocation:,这个消息只携带一个NSInvocation对象作为参数——这个NSInvocation对象包装了原始消息和相应参数。

通过实现forwardInvocation:方法(继承于NSObject),可以给不响应的消息一个默认处理方式。正如方法名一样,通常的处理方式就是转发该消息给另一个对象:

//////////////////////////////////////////////////////////////
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
     if ([someOtherObject respondsToSelector:[anInvocation selector]])
          [anInvocation invokeWithTarget:someOtherObject];
     else
          [super forwardInvocation:anInvocation];
}
//////////////////////////////////////////////////////////////

对于不识别的消息(在dispatch table中找不到),forwardInvocation:就像一个中转站,想继续投递或者停止不处理,都由开发人员决定。


[5] 类型编码

为了支持Runtime System,编译器将返回值类型、参数类型进行编码,相应的编译器指示符是@encode

比如,void编码为v,char编码为c,对象编码为@,类编码为#,选择符编码为:,而符合类型则由基本类型组成,比如

typedef struct example {
     id     anObject;
     char *aString;
     int anInt;
} Example;

编码为{example=@*i}。


[6] 属性声明

当编译器遇到属性声明时,它会生成一些可描述的元数据(metadata),将其与相应的类、category和协议关联起来。存在一些函数可以通过名称在类或者协议中查找这些metadata,通过这些函数,我们可以获得编码后的属性类型(字符串),复制属性的attribute列表(C字符串数组)。因此,每个类和协议的属性列表我们都可以获得。


与类型编码类似,属性类型也有相应的编码方案,比如readonly编码为R,copy编码为C,retain编码为&等。

通过property_getAttributes函数可以后去编码后的字符串,该字符串以T开头,紧接@encode type和逗号,接着以V和变量名结尾。比如:

@property char charDefault;

描述为:Tc,VcharDefault

@property(retain)ididRetain;

描述为:T@,&,VidRetain


Property结构体定义了一个指向属性描述符的不透明句柄:typedef struct objc_property *Property;

通过class_copyPropertyList和protocol_copyPropertyList函数可以获取相应的属性数组:

objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)

通过property_getName函数可以获取属性名称。

通过class_getProperty和protocol_getProperty可以相应地根据给定名称获取到属性引用:

objc_property_t class_getProperty(Class cls, const char *name)
objc_property_t protocol_getProperty(Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty)

通过property_getAttributes函数可以获取属性的@encode type string:

const char *property_getAttributes(objc_property_t property)


以上函数组合成一段示例代码:

@interface Lender : NSObject {
     float alone;
}
@property float alone;
@end

id LenderClass = objc_getClass("Lender");
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
for (i = 0; i < outCount; i++) {
     objc_property_t property = properties[i];
     fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
}


[Last Updated] 2012-03-17

参考资料:Objective-C Runtime Programming Guide


Jason Lee @ 杭州

博客:http://blog.csdn.net/jasonblog

微博:http://weibo.com/jasonmblog

GitHub:https://github.com/siqin

分享到:
评论

相关推荐

    Pro Objective-C

    After reviewing the basics, it proceeds with an in-depth examination of the Objective-C dynamic programming features and runtime system. Next the book covers the Foundation Framework, the base layer ...

    The Objective-C Programming Language

    Objective-C is defined as a small but powerful set of extensions to the standard ANSI C language. Its additions to C are mostly based on Smalltalk, one of the first object-oriented programming ...

    Learn Objective-C for Java Developers 2009 (Apress)

    It will show them how to take their existing language knowledge and design patterns and transfer that experience to Objective-C and the Cocoa runtime library. This is the express train to ...

    Objective-C Runtime Programming Guide

    You should read this document to gain an understanding of how the Objective-C runtime system works and how you can take advantage of it. Typically, though, there should be little reason for you to ...

    Objective-C Programming: The Big Nerd Ranch Guide (2nd Edition)

    C Bootcamp, Objective-C Programming: The Big Nerd Ranch Guide covers C, Objective-C, and the common programming idioms that enable developers to make the most of Apple technologies. Compatible with ...

    Objective-C Pocket Reference

    In addition to covering the essentials of Objective-C syntax, it also covers important facets of the language such as memory management, the Objective-C runtime, dynamic loading, distributed objects,...

    The Objective-C Programming Language-2006.pdf

    Objective-C is defined as small but powerful set of extensions to the standard ANSI C language. Its additions to C are mostly based on Smalltalk, one of the first object-oriented programming ...

    objective-c programming language

    This document is about the first component of the development environment—the programming language and its runtime environment. It fully describes the Objective-C language, and provides a foundation...

    Android代码-AJavatoiOSObjective-Ctranslationtoolandruntime

    J2ObjC: Java to Objective-C Translator and Runtime Project site: J2ObjC blog: Questions and discussion: What J2ObjC Is J2ObjC is an open-source command-line tool from Google that translates Java ...

    Programming in Objective-C 4th Edition

    An Objective-C Class for Working with Fractions 30 The @interface Section 33 Choosing Names 34 Class and Instance Methods 35 The @implementation Section 37 The program Section 39 Accessing Instance ...

    objc-lisp-bridge:便携式阅读器和桥接器,可与Objective-C和Cocoa进行交互

    CCL和LispWorks以及其他实现都有它们自己与Objective-C运行时的桥梁。 该项目试图创建仅使用CFFI的网桥,以便任意lisp实现都可以生成本机mac GUI。 从长远来看,我希望以此为基础为McClim提供新的mac-native后端:...

    Professional.Swift.1119016770

    Transition from Objective-C to the cleaner, more functional Swift quickly and easily Professional Swift shows you how to create Mac and iPhone applications using Apple's new programming language. ...

    ObjC.pdf 英文

    learning about the second component, the Mac OS X Objective-C application frameworks—collectively known as Cocoa. You can start to learn more about Cocoa by reading Getting Started with Cocoa. The ...

    Objective C开发教程

    This document is about the first component of the development environment—the programming language and its runtime environment. It fully describes the Objective-C language, and provides a foundation ...

    iOS 4 高级编程

    • The Objective-C programming language and runtime • Collections • Cocoa Touch • Interface Builder • Building advanced mobile user interfaces • Core Animation and Quartz 2D • Model-view-...

    Advanced Apple Debugging & Reverse Engineering v0.9.5

    You’ll cap off this round of dynamic framework exploration by digging into Objective-C frameworks using the Objective-C runtime to hook and execute methods of interest. 17. Hello Script Bridging ...

    iOS.Recipes(第1版)

    This book walks you through clean, reusable solutions to a wide variety of problems and patterns common to iOS development with Cocoa Touch and Objective-C. With these recipes in your arsenal, your ...

    iOS 6 Programming Cookbook

    Define the layout of UI elements with Cocoa Auto Layout Develop location-aware apps Get working examples for implementing gesture recognizers Use new Objective-C Runtime features Play audio and video...

    MinGW full 2009-04-10 Windows下的GNU编译器

    MinGW provides a complete Open Source programming tool set which is suitable for the development of native MS-Windows applications, and which do not depend on any 3rd-party C-Runtime DLLs. (It does ...

Global site tag (gtag.js) - Google Analytics