Learn Objective-C, Objects (Part 7): Introspection

Introspection is that ability to ask questions about a class and find out more of its properties. This is a fundamental concept of a group of concepts known as polymorphism, dynamic typing, and dynamic binding, which form a central tenet of object-oriented programming. Before we begin, there is another part of the language that we have to cover.

Selector (@selector())

Remember how methods are also known as selectors (because a method is selected at runtime)? Turns out, you can select a method yourself, and pass it as an argument to a method. The syntax is simple:

@selector(methodSignature)

Remember that a method signature includes its colons, such as setNumerator:overDenominator: (if appropriate).

You can declare a selector as a variable to be used in multiple places with the following syntax:

SEL action = @selector(doSomethingWithObject:)

Note that a selector is of type SEL.

Introspection Methods

Here is a list of most of the introspection methods. A few deal with some more advanced topics, such as protocols; they will be introduced in context. Note that the classType argument refers to an object’s class, which is returned by invoking the class method, as in [Fraction class];.

Working off our Fraction and MixedNumber classes, we can have the following routine:

int main (int argc, const char *argv[]) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    Fraction *frac = [[Fraction alloc] init];
    MixedNumber *mn = [[MixedNumber alloc] init];

    if ([frac isMemberOfClass:[Fraction class]])
        NSLog(@"frac is member of Fraction class");
    if ([mn isMemberOfClass:[Fraction class]])
        NSLog(@"mn is member of Fraction class");
    if ([mn isMemberOfClass:[NSObject class]])      // Remember that everything
        NSLog(@"mn is member of NSObject class"); // inherits from NSObject

    if ([frac isKindOfClass:[Fraction class]])
        NSLog(@"frac is kind of Fraction class");
    if ([mn isKindOfClass:[Fraction class]])
        NSLog(@"mn is kind of Fraction class");
    if ([frac isKindOfClass:[NSObject class]])
        NSLog(@"frac is kind of NSObject class");

    if ([frac respondsToSelector:@selector(add:)])
        NSLog(@"frac responds to add:");
    if ([mn respondsToSelector:@selector(add:)])
        NSLog(@"mn responds to add:");
    if ([Fraction respondsToSelector:@selector(alloc)])
        NSLog(@"Fraction class responds to alloc");

    if ([Fraction instancesRespondToSelector:@selector(subtract:)])
        NSLog(@"Instances of Fraction respond to subtract:");

    if ([MixedNumber isSubclassOfClass:[Fraction class]])
        NSLog(@"MixedNumber is a subclass of Fraction");

    [frac release];
    [mn release];
    [pool drain];
    return 0;
}

The output is

frac is member of Fraction class
frac is kind of Fraction class
mn is kind of Fraction class
frac is kind of NSObject class
frac responds to add:
mn responds to add:
Fraction class responds to alloc
Instances of Fraction respond to subtract:
MixedNumber is a subclass of Fraction

Introspection really isn’t a difficult topic- the only potential source of error stems from confusing the functionality of isKindOfClass: and isMemberOfClass:. Somehow, just remember that isKindOfClass: involves descendants (subclasses), while isMemberOfClass: does not.

This post is part of the Learn Objective-C in 24 Days course.


Previous Lesson Next Lesson