| < Previous PageNext Page > |
Just by themselves, the Objective-C language and runtime are not enough to construct even the simplest object-oriented program, at least not easily. Something is still missing: a definition of the fundamental behavior and interface common to all objects. A root class supplies that definition.
A root class is so-called because it lies at the root of a class hierarchy—in this case, the Cocoa class hierarchy. The root class inherits from no other class, and all other classes in the hierarchy ultimately inherit from it. Along with the Objective-C language, the root class is primarily where Cocoa directly accesses and interacts with the Objective-C runtime. Cocoa objects derive the ability to behave as objects in large part from the root class.
Cocoa supplies two root classes: NSObject and NSProxy. Cocoa defines the latter class, an abstract superclass, for objects that act as stand-ins for other objects; thus NSProxy is essential in the distributed objects architecture. Because of this specialized role, NSProxy appears infrequently in Cocoa programs. When Cocoa developers refer to a root or base class, they almost always mean NSObject.
This section looks at NSObject, how it interacts with the runtime, and the basic behavior and interface it defines for all Cocoa objects. Primary among these are the methods it declares for allocation, initialization, memory management, introspection, and runtime support. These concepts are fundamental to an understanding of Cocoa.
NSObject
Root Class—and Protocol
Overview of Root-Class Methods
Interface Conventions
Instance and Class Methods
NSObject is the root class of most Objective-C class hierarchies; it has no superclass. From NSObject, other classes inherit a basic interface to the run-time system for the Objective-C language, and its instances obtain their ability to behave as objects.
Although it is not strictly an abstract class, NSObject is virtually one. By itself, an NSObject instance cannot do anything useful beyond being a simple object. To add any attributes and logic specific to your program, you must create one or more classes inheriting from NSObject or from any other class derived from NSObject.
NSObject adopts the NSObject protocol (see “Root Class—and Protocol”). The NSObject protocol allows for multiple root objects. For example, NSProxy, the other root class, does not inherit from NSObject but adopts the NSObject protocol so that it shares a common interface with other Objective-C objects.
NSObject, along with java.lang.Object, is the root class for all things Cocoa in Java, including Foundation and Application Kit.
NSObject is the name not only of a class but of a protocol. Both are essential to the definition of an object in Cocoa. The NSObject protocol specifies the basic programmatic interface required of all root classes in Cocoa; thus not only the NSObject class adopts the identically named protocol, but the other Cocoa root class, NSProxy, adopts it as well. The NSObject class further specifies the basic programmatic interface for any Cocoa object that is not a proxy object.
A protocol such as NSObject is used in the overall definition of Cocoa objects (rather than including those protocol methods in the class interface) to make multiple root classes possible. Each root class shares a common interface, as defined by the protocols they adopt.
In another sense, NSObject is not the only “root” protocol. Although the NSObject class does not formally adopt the NSCopying, NSMutableCopying, and NSCoding protocols, it declares and implements methods related to those protocols. (Moreover, the NSObject.h header file, which contains the definition of the NSObject class, also contains the definitions of all four protocols mentioned above.) Object copying, encoding, and decoding are fundamental aspects of object behavior. Many, if not most, subclasses are expected to adopt or conform to these protocols.
Note: Other Cocoa classes can (and do) add methods to NSObject through categories. These categories are often informal protocols used in delegation; they permit the delegate to choose which methods of the category to implement. However, these categories on NSObject are not considered part of the fundamental object interface.
The NSObject root class, along with the adopted NSObject protocol and other “root” protocols, specify the following interface and behavioral characteristics for all non-proxy Cocoa objects:
Allocation, initialization, and duplication. Some methods of NSObject (including some from adopted protocols) deal with the creation, initialization, and duplication of objects:
The alloc and allocWithZone: methods allocate memory for an object from a memory zone and set the object to point to its runtime class definition.
The init method is the prototype for object initialization, the procedure that sets the instance variables of an object to a known initial state. The class methods initialize and load give classes a chance to initialize themselves.
new is a convenience method that combines simple allocation and initialization.
The copy and copyWithZone: methods make copies of any object that is a member of a class implementing these methods (from the NSCopying protocol); the mutableCopy and mutableCopyWithZone: (defined in the NSMutableCopying protocol) are implemented by classes that want to make mutable copies of their objects.
See “Object Creation” for more information.
Object retention and disposal. The following methods are particularly important to memory management in an object-oriented program:
The retain method increments an object’s retain count.
The release method decrements an object’s retain count.
The autorelease method also decrements an object’s retain count, but in a deferred fashion.
The retainCount method returns an object’s current retain count.
The dealloc method is implemented by class to release its objects’ instance variables and free dynamically allocated memory.
See the “The Life Cycle of a Cocoa Object” for more information.
Introspection and comparison. Many NSObject methods enable you to make runtime queries about an object. These introspection methods help to discover an object’s position in the class hierarchy, determine whether it implements a certain method, and test whether it conforms to a specific protocol. Some of these are class methods only.
The superclass and class methods (class and instance) return the receiver’s superclass and class, respectively, as Class objects.
You can determine the class membership of objects with the methods isKindOfClass: and isMemberOfClass:; the latter method is for testing whether the receiver is an instance of the specified class. The class method isSubclassOfClass: tests class inheritance.
The respondsToSelector: method tests whether the receiver implements a method identified by a selector. The class method instancesRespondToSelector: tests whether instances of a given class implement the specified method.
The conformsToProtocol: method tests whether the receiver (object or class) conforms to a given protocol,.
The isEqual: and hash methods are used in object comparison.
The description method allows an object to return a string describing its contents; this output is often used in debugging (“print object” command) and by the “%@” specifier for objects in formatted strings.
See “Introspection” for more information.
Object encoding and decoding. The following methods pertain to object encoding and decoding (as part of the archiving process):
The encodeWithCoder: and initWithCoder: methods are the sole members of the NSCoding protocol. The first allows an object to encode its instance variables and the second enables an object to initialize itself from decoded instance variables.
The NSObject class declares other methods related to object encoding: classForCoder:, replacementObjectForCoder:, and awakeAfterUsingCoder:.
See Archives and Serializations Programming Guide for Cocoa for further information.
Message forwarding. The forwardInvocation: and related methods permit an object to forward a message to another object.
Message dispatch. A set of methods beginning with performSelector...) allow you to dispatch messages after a specified delay and to dispatch messages (synchronously or asynchronously) from a secondary thread to the main thread.
NSObject has several other methods, including class methods for versioning and posing (the latter lets a class present itself to the runtime as another class). It also includes methods that let you access runtime data structures, such as method selectors and function pointers to method implementations.
Some NSObject methods are meant only to be invoked while others are intended to be overridden. For example, most subclasses should not override allocWithZone: but they should implement init—or at least an initializer that ultimately invokes the root-class init method (see “Object Creation”). Of those methods that subclasses are expected to override, NSObject’s implementation either does nothing or returns some reasonable default value such as self. These default implementations make it possible to send basic messages such as init to any Cocoa object—even to an object whose class doesn’t override them—without risking a runtime exception. It’s not necessary to check (using respondsToSelector:) before sending the message. More importantly, the “placeholder” methods of NSObject define a common structure for Cocoa objects and establish conventions that, when followed by all classes, make object interactions more reliable.
The runtime system treats methods defined in the root class in a special way. Instance methods defined in a root class can be performed both by instances and by class objects. Therefore, all class objects have access to the instance methods defined in the root class. Any class object can perform any root instance method, provided it doesn’t have a class method with the same name.
For example, a class object could be sent messages to perform NSObject’s respondsToSelector: and performSelector:withObject: instance methods:
SEL method = @selector(riskAll:); |
if ([MyClass respondsToSelector:method]) |
[MyClass performSelector:method withObject:self]; |
Note that the only instance methods available to a class object are those defined in its root class. In the example above, if MyClass had re-implemented either respondsToSelector: or performSelector:withObject:, those new versions would be available only to instances. The class object for MyClass could perform only the versions defined in the NSObject class. (Of course, if MyClass had implemented respondsToSelector: or performSelector:withObject: as class methods rather than instance methods, the class would perform those new versions.)
| < Previous PageNext Page > |
© 2006 Apple Computer, Inc. All Rights Reserved. (Last updated: 2006-12-20)
|