Objective-C is an extension to regular C. So of course, at some point there is a place where all the new stuff in Objective-C ties into regular C. This Extension covers this happy meeting place. Some of the concepts may be a bit foreign, but they will be further explained in later Lessons.
Objects are Represented as Structs in Memory
You may have noticed that accessing a member of a struct uses dot notation, the same way you could access instance variables in your objects. This is because the ivars are actually stored inside a struct, which holds your instance variables plus any inherited ones. The alloc method reserves enough memory space to hold one of these structs.
Speaking of inherited instance variables, every class inherits a variable called isa (is-a) which identifies the object’s class—that is how the runtime system figures out the identity of the object, even if it’s assigned to a generic id type.
id is a Generic Pointer Type
The id type can be used for any object type. The id type is a generic pointer, which means that it is simply a memory address. The system at compile time does not know about the type of the object (that is what the isa variable is for), but simply that there is a location of memory involved. Because of this, and the fact that all objects reside in memory, the id pointer can be reassigned to different object type variables as needed.
An Object is Always Used as a Pointer
The asterisk associated with every object type is a pointer—a variable that actually holds as its value a memory address. A declaration such as
Fraction *myFract; means that you’re defining a pointer, which will point to something in memory of type Fraction.
The reason everything is passed as pointers is one of performance. A memory address is a much smaller amount of storage than the actual object. On a 32-bit system, a memory address takes up 32 bits—usually the same size as an int. On a 64-bit system, an address would take up 64 bits. While it may seem a bit redundant at first to store memory addresses in memory, it starts to make more sense when you realize that you could have an object that holds several kilobytes of data in one object—it’s a lot faster an easier to copy 64 bits than several thousand of them.
The alloc method returns an object pointer of type id. You can then assign this pointer value to any other pointer value—in this case, perhaps a type Fraction.
When you assign one pointer to another, as in
fract1 = fract2;
You’re still assigning the value of fract2 to fract1—but remember that the value of fract2 is a memory address. So you’re making fract1 refer to the same location in memory as fract2. Therefore, anything you do to fract2 will be reflected in fract1—because of course they now refer to the same actual object in memory.
The Dual-Nature of Objects
An Objective-C object consists of instance variables and methods. The ivars are stored as a struct, and referred to using more efficient pointers. Methods are not stored in memory. Instead, methods (which are conceptually different from functions—the former is specific to a class, while the latter is global) are placed in a pool of methods, associated with the class name, and “selected” as needed.
This post is part of the Learn Objective-C in 24 Days course.
Author: Feifan Zhou