Runtime Environment

When 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.

Class Objects

Class 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:

ClasscircleClass = [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.

isa and super_class define the inheritance chain

Figure 1-1. isa and super_class define the inheritance chain

Runtime method dispatch for regular objects follows this sequence:

  1. Follow the receiver’s isa member to its class object.

  2. Search for the method in the class object’s method list.

  3. If the method is not found, follow the class object’s super_class pointer to the parent class.

  4. Repeat steps 2-3 until the method is found, or the root class’s super_class pointer (which is Nil) is evaluated.

  5. If the message is still not handled, call the object’s -forward:: method. Both Object and NSObject provide this method. (NSObject’s version is private.) The default forwarding behavior is to abort the program.

  6. If the object has no forwarding method, the program exits with an error.

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.

Metaclass Objects

If 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.

Note

The isa field of a class object is not inherited from a root class, but specified in the declaration of Class in objc.h. Its name varies across implementations; this handbook uses isa for clarity. isa is the name used in Darwin.

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.

Classes and their metaclasses

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.

Note

The GNU runtime distinguishes between class and metaclass objects more than the Darwin runtime does. In the GNU runtime there are distinct Class and MetaClass types (although they are just typedefs for identical structures). Some of the reflection methods (like -isKindOf:) of Object behave differently from the Darwin version when passed metaclass objects. The exact behavior of these methods is described in the Section 1.10.

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.

Selectors

For 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.)

Protocol Objects

The 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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.240.244