| I l@ve RuBoard |
|
1.9 Runtime EnvironmentWhen your Objective-C program is running, certain structures and services are always set up for you, even though you don't specifically ask for them. These serve as the counterpart to the compiler: together the compiler and the runtime implement the features that Objective-C adds to C. Most languages include runtime environments; Objective-C is distinctive in exposing a good part of its runtime in a public programming interface. The runtime's interfaces are in header files that will be present in any installation of gcc. (For example, in Darwin they reside at /usr/include/objc. Check your compiler's default include paths to locate these files.) You can also download the source code for the runtime; examining it is a good way to learn more about how dynamic languages are implemented. 1.9.1 Class ObjectsClass objects are objects that represent at runtime the classes a program is using. Because they function in the same way as regular objects—you can send them messages and use them in expressions—Objective-C unifies the treatment of classes and their instances. Class objects are also called factory objects, because in their most common usage you send them the +alloc message to create other objects. Class objects are set up by the Objective-C compiler and initialized at runtime before your code needs to use them. To get a class object from an instance, use the -class method. For example, given an instance created this way: Circle* c = [Circle new]; you can retrieve the class object of that instance like this: Class circleClass = [c class]; Sending a message to a class object is common enough that it has a shortcut: just name the class as the receiver, as you do when you invoke +alloc. In the Objective-C runtime all regular objects start with an isa field, pointing to their class object. The class object contains (or refers to) the instance methods that the object can respond to. In addition each class object has a super_class pointer which refers to the parent class object. For root classes—those that have no parents—super_class is set to Nil. Figure 1-1 illustrates how isa and super_class work together to define the inheritance-chain for an object of class C, which inherits from class B and the root class. Figure 1-1. isa and super_class define the inheritance chain![]() Runtime method dispatch for regular objects follows this sequence:
The call to the forwarding method completes the method dispatcher's role in performing the original method call: it has now been transformed into a different call (which is dispatched with the same mechanism). The Section 1.11 describes the subsequent steps in processing an unhandled message. 1.9.2 Metaclass ObjectsIf instance methods are stored in class objects, then where are class methods stored? Class objects themselves have other objects to store the methods they respond to; these are called metaclass objects. Like regular objects, class objects point to their metaclass objects with an isa field.
This design allows class method invocation and lookup to proceed exactly the same way as for instance methods. Class objects stand on an equal footing with other objects in Objective-C: you can assign them to variables declared as id, send messages to them, and they inherit (class) methods from their ancestors. The runtime relation between classes and their metaclasses is illustrated in Figure 1-2. Figure 1-2. Classes and their metaclasses![]() Metaclass objects are identical in structure to class objects. However, their isa pointers all refer to the root metaclass. This is a practical measure to forestall the need for an infinite hierarchy of meta-metaclasses. (Effectively, the root class is the meta-metaclass of all its descendants.) Since you don't normally use metaclass objects, this is not a major blemish on the consistency of Objective-C.
Figure 1-2 shows one other distinctive asymmetry in the otherwise uniform structure of the runtime environment: the root metaclass's super_class pointer refers to the root class object. This means that class objects behave as if they are instances of their root class: class objects will respond not only to their own class messages and those of their parent classes (including those of the root), but also to instance messages of the root class. 1.9.3 SelectorsFor efficiency, method dispatch doesn't look up method names with string comparisons. Instead method names are mapped one-to-one with selectors—variables of type SEL. This mapping is known to both the compiler and the runtime system. If you want pass a method around as a parameter and invoke it through that parameter, you can use a SEL along with one of the -perform: methods. (The Section 1.3.5 gives an example of this.) 1.9.4 Protocol ObjectsThe runtime also defines objects for each protocol in your program. You can retrieve these objects using the @protocol directive: Protocol* p = @protocol (ProtocolName ); You can't do much with a protocol instance except pass it to root class methods that take protocols as parameters, or send the -conformsTo: message to it in order to see whether it conforms to yet another protocol. |
| I l@ve RuBoard |
|