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(methodName)**

Remember that a method name 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];.

  • -(BOOL)isKindOfClass:classType Is the object a member of that class or a subclass?
  • -(BOOL)isMemberOfClass:classType Is the object a member of that class? *-(BOOL)respondsToSelector:aSelector Does an object (class or instance) respond to the selector’s method? *+(BOOL)instancesRespondToSelector:aSelector Do instances of the class respond to the selector’s method? *+(BOOL)isSubclassOfClass:classType Is this class a subclass of the specified class? *-(id)performSelector:aSelector Ask the class to perform the method specified by the selector, returning whatever the method is intended to return. *-(id)performSelector:aSelector withObject:someObject Performs the selector, passing in someObject as the first (and hopefully only) argument, returning whatever the method is designed to return. *-(id)performSelector:aSelector withObject:someObject withObject:anotherObject Perform the selector, passing in the two arguments in that order to the (assumed) two parameters defined by the selector, returning whatever the method is designed to return.

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.

0 comments


Or enter your name and Email
No comments have been posted yet.