1.20. Determining Whether Instance or Class Methods Are Available

Problem

Your development SDK is the newest SDK, but you want to support devices running older iOS versions and APIs.

Solution

Use the instancesRespondToSelector: class method of NSObject to determine whether a specific selector exists in an instance of that class.

Note

A selector is the name of your method without the parameter data types. For instance, given the following method declaration:

- (BOOL) doesString:(NSString *)paramNeedle
      existInString:(NSString *)paramHaystack;

The selector for this method would be doesString:existInString:.

To determine whether a class itself responds to a class method, use the respondsToSelector: class method of your class. You can use the same method on an instance of a class to determine whether that instance responds to an instance method, as well as the instancesRespondToSelector: class method of the NSObject class.

Discussion

There are two important concepts with regard to iOS SDK that you need to remember:

Base SDK

The SDK that you use to compile your application. This can be the latest and the greatest SDK with access to all the new APIs available in iOS SDK.

Deployment SDK/Target

This is the SDK that will be used when you compile your app to run on devices.

Because of the fact that you are essentially compiling your apps with two SDKs, one the base and the other the deployment SDK, depending on which profile you are using (device or simulator), your program might be vulnerable to invoking methods in classes that are available only in the latest SDK, but not the deployment SDK. So you might need to check from time to time for the existence of instance or class methods at runtime.

Let me give you an example. The iOS SDK has a class called NSArray. As you will see in Recipe 1.23, you can simply allocate and initialize an object of this type and start using its methods. A mutable array (an array that can be changed after it has been constructed) is of type NSMutableArray and offers sorting mechanisms that you can use to sort the elements inside the array. There are various sorting methods, some of which are available only in newer SDKs. So what you can do is determine which of the sorting (instance) methods are available at runtime and then use those methods to sort the array:

NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:
                         @"Item 1",
                         @"Item 4",
                         @"Item 2",
                         @"Item 5",
                         @"Item 3", nil];

NSLog(@"Array = %@", array);

if ([NSArray instancesRespondToSelector:@selector(sortUsingComparator:)]){

  /* Use the sortUsingComparator: instance method of the array to sort it */

}
else if ([NSArray instancesRespondToSelector:
          @selector(sortUsingFunction:context:)]){

  /* Use the sortUsingFunction:context: instance
   method of the array to sort */

}
else {

  /* Do something else */

}

So in this example, we are checking the existence of the specific instance methods using the instancesRespondToSelector: class method of the NSMutableArray class (which itself is a subclass of NSArray). Alternatively, we could use the respondsToSelector: instance method of our array:

NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:
                         @"Item 1",
                         @"Item 4",
                         @"Item 2",
                         @"Item 5",
                         @"Item 3", nil];

NSLog(@"Array = %@", array);

if ([array respondsToSelector:@selector(sortUsingComparator:)]){

  /* Use the sortUsingComparator: instance method of the array to sort it */

}
else if ([array respondsToSelector:@selector(sortUsingFunction:context:)]){

  /* Use the sortUsingFunction:context: instance
   method of the array to sort */

}
else {
  /* Do something else */
}

Fantastic. We checked the existence of instance methods. How about class methods? The NSArray class again has various class methods, two of which are the arrayWithObjects: and the arrayWithObjects:count: methods. We can determine their availability at runtime and use them to initialize the array:

NSArray *array = nil;

if ([NSArray respondsToSelector:@selector(arrayWithObjects:count:)]){
  NSString *strings[4];
  strings[0] = @"String 1";
  strings[1] = @"String 2";
  strings[2] = @"String 3";
  strings[3] = @"String 4";

  array = [NSArray arrayWithObjects:strings
                              count:4];
}
else if ([NSArray respondsToSelector:@selector(arrayWithObjects:)]){
  array = [NSArray arrayWithObjects:
           @"String 1",
           @"String 2",
           @"String 3",
           @"String 4",
           nil];
}
else {
  /* Do something else */
}

NSLog(@"Array = %@", array);

See Also

Recipe 1.23

Get iOS 6 Programming Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.