I mentioned before that classes are the fundamental unit of OOP. Classes serve as a blueprint for creating any number of objects that actually do the work at runtime. Objects are runtime manifestations of a class that exist in a computer's memory.
Classes define in source code the data structures and any number of functions that can use or modify these data structures. The data structures are called instance variables, and the functions are called methods. In this way, objects are endowed with a state determined by the instance variables and a particular behavior defined by the methods.
I think Apple described the basic premise of OOP best in their book Object-Oriented Programming and The Objective-C Language: "The insight of object-oriented programming is to combine state and behavior -- data and operations on data -- in a high-level unit, and object, and to give it language support."
To understand the nature of objects, you must first understand how methods and data interact. Methods can be envisioned as wrapping around the data contained by an object, protecting it from the environment in which the object exists. In this way, the focus of programming shifts from thinking about data, to thinking about the various actions objects can perform.
For example, it's very rare that object instance variables would be directly accessible by another object. Rather, special methods called accessor methods allow other objects to access variable values by invoking these methods that return the value of the instance variables.
Objects communicate with each other by sending messages. A message is a command to some receiver object (or simply the receiver) to perform some action by invoking one of its methods. In this way, objects in a complicated application send messages back and forth and amongst each other -- messages to obtain data, perform actions, store data, or whatever.
You could think of an application as a network of objects that are constantly communicating with each other to serve the end purpose of the application. This metaphor is so powerful, in fact, that objects are often referred to as either servers or clients. Clients request services of server objects that provide the requested service.
One of the most important concepts of object-oriented programming is inheritance. The idea behind inheritance is that new classes are created by inheriting and adding to the behavior and characteristics of some pre-existing class (a parent class). The parent class is called a superclass and the new class is a subclass.
In this scheme, subclasses specialize the functionality of their parent classes by adding to and customizing the inherited behavior. For example, in The Application Kit, the NSButton class is a subclass of the NSControl class, and thus inherits all properties and functionality of a control as defined in NSControl.
Inheritance naturally leads to a large-scale organization of classes that is hierarchical, like the roots of a tree. If you follow this back far enough, you arrive at a common class which all other classes inherit -- a root object. The Foundation Framework contains the root class of all Cocoa classes. Appropriately, this class is called NSObject, and it defines the basic behavior that makes an object an object.
Inheritance is useful in many ways. It allows you to reuse code that has been tested and is known to work well, meaning there's less chance of bugs creeping into your code. Additionally, inheritance provides some unique design solutions found only in OOP.
If you have many classes that implement some common behavior, you can extract that into a superclass from which they all inherit. This makes maintenance easier since updating one class effectively updates the entire tree of subclasses below it.
For example, say you have a graphics program that works with circles, squares, and rectangles. As far as the drawing program is concerned, the classes controlling these shapes will share a great deal of code that does not relate to the actual shape we see on screen. This common code could then be extracted to a superclass called
Shape from which
Circle would inherit and customize to their needs. This is the way inheritance makes things easier for us.
Another use for inheritance is to declare a number of methods in a class that its child classes may implement in their own unique way. These methods may be empty or partially implemented, but their purpose is to inform us that subclasses of this class need to implement these methods in their own way. This is known as a protocol.
Objective-C provides ways to create more formal protocols which are not associated with any particular class. As before, these formal protocols provide a set of method declarations that must be defined by classes that conform to this protocol. Cocoa makes extensive use of protocols, and these protocols will be discussed in their own right in later columns.