As the name implies, object-oriented programs are built around objects. An object associates data with the particular operations that can use or affect that data. In Objective-C, these operations are known as the object’s methods; the data they affect are its instance variables. In essence, an object bundles a data structure (instance variables) and a group of procedures (methods) into a self-contained programming unit.
For example, if you are writing a drawing program that allows a user to create images composed of lines, circles, rectangles, text, bit-mapped images, and so forth, you might create classes for many of the basic shapes that a user can manipulate. A Rectangle object, for instance, might have instance variables that identify the position of the rectangle within the drawing along with its width and its height. Other instance variables could define the rectangle’s color, whether or not it is to be filled, and a line pattern that should be used to display the rectangle. A Rectangle class would have methods to set an instance’s position, size, color, fill status, and line pattern, along with a method that causes the instance to display itself.
In Objective-C, an object’s instance variables are internal to the object; generally, you get access to an object’s state only through the object’s methods (you can specify whether subclasses or other objects can access instance variables directly by using scope directives, see “The Scope of Instance Variables”). For others to find out something about an object, there has to be a method to supply the information. For example, a Rectangle would have methods that reveal its size and its position.
Moreover, an object sees only the methods that were designed for it; it can’t mistakenly perform methods intended for other types of objects. Just as a C function protects its local variables, hiding them from the rest of the program, an object hides both its instance variables and its method implementations.
In Objective-C, object identifiers are a distinct data type: id. This type is defined as a pointer to an object—in reality, a pointer to the instance variables of the object, the object’s unique data. Like a C function or an array, an object is identified by its address. All objects, regardless of their instance variables or methods, are of type id.
id anObject; |
For the object-oriented constructs of Objective-C, such as method return values, id replaces int as the default data type. (For strictly C constructs, such as function return values, int remains the default type.)
The keyword nil is defined as a null object, an id with a value of 0. id, nil, and the other basic types of Objective-C are defined in the header file objc/objc.h.
The id type is completely nonrestrictive. By itself, it yields no information about an object, except that it is an object.
But objects aren’t all the same. A Rectangle won’t have the same methods or instance variables as an object that represents a bit-mapped image. At some point, a program needs to find more specific information about the objects it contains—what the object’s instance variables are, what methods it can perform, and so on. Since the id type designator can’t supply this information to the compiler, each object has to be able to supply it at runtime.
This is possible because every object carries with it an isa instance variable that identifies the object’s class—what kind of object it is. Every Rectangle object would be able to tell the runtime system that it is a Rectangle. Every Circle can say that it is a Circle. Objects with the same behavior (methods) and the same kinds of data (instance variables) are members of the same class.
Objects are thus dynamically typed at runtime. Whenever it needs to, the runtime system can find the exact class that an object belongs to, just by asking the object. Dynamic typing in Objective-C serves as the foundation for dynamic binding, discussed later.
The isa pointer also enables objects to perform introspection—to find out about themselves (or other objects). The compiler records information about class definitions in data structures for the runtime system to use. The functions of the runtime system use isa, to find this information at runtime. Using the runtime system, you can, for example, determine whether an object implements a particular method, or discover the name of its superclass.
Object classes are discussed in more detail under “Classes.”
It’s also possible to give the compiler information about the class of an object by statically typing it in source code using the class name. Classes are particular kinds of objects, and the class name can serve as a type name. See “Class Types” and “Enabling Static Behavior.”
Last updated: 2008-02-05