David Ogren
David Ogren

Reputation: 4800

What is the naming convention for methods you know will appear in a later SDK?

I realize that there is some subjectivity in the question, but considering that Apple development is pretty opinionated about naming conventions I want to do this in the way that others will understand what my coding is doing. I am trying to ask the question in the most generic way, But I'll add some of my specific details in the comments in case it affects your answer.

Let's say that I am supporting both iOS 6 and iOS 7. There is a new method on an existing class that only exists in the iOS 7 SDK. Assume that implementing the functionality in a way that is "good enough" for my app is fairly straightforward. But, of course, I'd rather use the SDK version as it is likely to be better supported, more efficient, and better handle edge cases.

As documented in this Q&A it is straightforward to handle this situation.

if ([myInstance respondsToSelector:@selector(newSelector)]) {
    //Use the SDK method
} else {
    //Use my "good enough" implementation.
}

But I don't want to litter my code with a whole bunch of conditional invocations. It seems that it would be better to encapsulate this dynamic method selection. (Especially in my case, where the method hasn't actually shipped yet and the name/signature might change.)

My instinct is to add a class category that implements both my functionality as well as a wrapper method that implements this dynamic selection of method.

Is this the right approach? If so, what naming conventions should I use? (I obviously can't name my method the same as the iOS7 method or there would be naming collisions.)

My gut reaction is to call my wrapper method safeNewSelector and my implementation a private method called lwNewSelector (where lw is my standard class prefix). But I'd much rather use something that would be considered a standard naming convention.

Upvotes: 5

Views: 277

Answers (3)

DarkDust
DarkDust

Reputation: 92384

Go for a category and chose a name that is pretty unique, for example prefixed by some company/project specific prefix. Let's say the method in iOS 7 is going to be called funky and you chose the prefix foo. Then you'd do:

@implementation SomeClass(FooCategory)

- (void)foo_funky
{
   if ([self respondsToSelector:@selector(funky)]) {
      [self funky];
   } else {
      // Implementation of workaround.
   }
}

@end

Now, every time you'd call foo_funky that decision needs to be made. Pretty inefficient. It just occurred to me that Objective-C can make that more efficient by messing with the runtime, kind of like method-swizzling (following code is untested):

@implementation SomeClass(FooCategory)

- (void)foo_funky
{
    // Empty implementation, it will be replaced.
}

- (void)foo_myFunkyImplementation
{
    // Workaround implementation in case the iOS 7 version is missing.
}

+ (void)load
{
    Method realMethod, dummyMethod;

    realMethod = class_getInstanceMethod(self, @selector(funky));
    if (!realMethod) {
        // iOS7 method not available, use my version.
        realMethod = class_getInstanceMethod(self, @selector(foo_myFunkyImplementation));
    }

    // Get the method that should be replaced.
    dummyMethod = class_getInstanceMethod(self, @selector(foo_funky));

    // Overwrite the dummy implementation with the real implementation.
    method_setImplementation(dummyMethod, method_getImplementation(realMethod));
}

@end

This way every time you call foo_funky the correct method is called without the overhead of responds-to-selector-and-then-call-other-method.

You could also use the runtime class modifications to add your implementation using the official name when it's not available, but I don't recommend that. It's better when you can tell by the method name that it might not be the version you're expecting.

Upvotes: 2

Pascal
Pascal

Reputation: 16941

It is a fair question indeed and I think many Objective-C debs have run into this situation.

I have used the approach that you suggest, using a class category, in several places myself. As for the naming, in most cases I put a little extra functionality into my category method, so my method names most of the time take another argument – in most cases a simple animated:(BOOL)animated added to the end of the "official" method name.

Yes, there's a risk of clashing with future SDK releases, but I wouldn't worry too much about it, Xcode's refactoring works reasonably well and you'll get a linker warning when category methods conflict.

Edit: As Rob points out, using that naming convention is probably a good idea.

Upvotes: 0

Rob Napier
Rob Napier

Reputation: 299475

My instinct is to add a class category that implements both my functionality as well as a wrapper method that implements this dynamic selection of method.

That sounds right. The naming convention for category methods is a lowercase prefix, plus underscore. So, if you are shadowing a method called doSomething:withAwesome:, you would name your category method ogr_doSomething:withAwesome: (assuming you use OGR as your common prefix).

You really must prefix category methods. If two categories implement the same method, it is undefined behavior which will be run. You will not get a compile-time or runtime error. You'll just get undefined behavior. (And Apple can, and does, implement "core" functionality in categories, and you cannot easily detect that they've done so.)

Upvotes: 3

Related Questions