Understanding Class Objects and Selectors in Objective-C
The Nature of Class Objects
In Objectvie-C, a class is itself an object, known as a class object.
A class object persists throughout the runtime of the program. It is a data structure that stores essential information about the class, such as its size, name, version, and the dispatch table mapping selectors to method implementations. This information is determined at compile time and loaded into memory when the class is first used.
The class object represents the class. The Class type denotes a class object, and class methods belong to it. When a message receiver is a class name, that name refers to the class object.
During runtime, all instances of a class are created by its class object. The class object sets the instance's isa pointer too its own address, meaning every instance's isa points to its class object. From the class object, you can discover superclass information and the methods it can respond to.
Class objects can only use class methods, not instance methods.
Example:
Employee *emp = [Employee new]; // 'emp' is an instance object
// 'Employee' is also an object (a class object) of type Class
Obtaining a Class Object
You can retrieve a class object in two primary ways:
1. From an instance object:
Vehicle *car = [Vehicle new];
Vehicle *truck = [Vehicle new];
// Get the class object from instances
Class carClass = [car class];
Class truckClass = [truck class];
NSLog(@"%p", carClass);
NSLog(@"%p", truckClass); // Both will print the same address
2. Directly from the class name:
// The class name itself represents the class object
Class vehicleClass = [Vehicle class];
NSLog(@"%p", vehicleClass); // Same address as above
Using a Class Object
Traditionally, you use a class name to:
- Create instances:
[Person new]; - Call class methods:
[Person utilityMethod];
With a Class variable, you can perform similar operations:
Person *personInstance = [Person new];
Class personClass = [personInstance class]; // Get the Class object
// 1. Create a new instance using the Class object
Person *anotherPerson = [personClass new];
// 2. Call a class method using the Class object
// Asuming +staticMethod is a class method
[personClass staticMethod];
Note: [personInstance instanceMethod] calls an instance method (dynamic), while [personClass staticMethod] calls a class method (static).
The SEL Type
SEL (selector) is a type that represents the location of a method.
Method Lookup Process:
- The method name (e.g.,
display) is wrapped into aSELtype data. - The runtime uses this
SELto find the corresponding method address in the class's dispatch table. - The method at that address is invoked.
- This process employs caching. The first lookup can be expensive, but subsequent calls for the same selector are fast.
Every method implementation has access to the _cmd variable, which represents the current method's selector.
SEL is essentially a wrapper for a method name, enabling the runtime to find and call the method. Sending a message involves sending a SEL.
Example of using SEL:
// Manually create a SEL for the 'calculate' method
SEL actionSelector = @selector(calculate);
// Use performSelector: to invoke the method via the SEL
[myObject performSelector:actionSelector];