2

I have an objective-c class method, which for a given launch of the application will always return the same value; I remember reading somewhere that I could declare a function in such a way that the compiler would understand this and make appropriate optimisations.

(It may have had something to do with the static keyword, but I can't remember, and Google only tells me "they're not static methods, they're class methods", which isn't what I'm talking about at all.)

My specific situation—though the question applies to any function or method—is a category on UIColor, which returns application-specific colour values in a similar way to [UIColor redColor] et. al. While these colours may be customised per device and may change from one run to the next, they will always be the same value for each run of the application.

While I'm also interested in whether there's particular value in any such optimisations, I'm far more interested in the actual declaration. I'm happy to hear if I'm "doing it wrong," but I'd also like to hear how I can actually declare a function or method in this manner.

UPDATE: It has nothing to do with static; sorry, that was irrelevant.

Calrion
  • 3,202
  • 1
  • 28
  • 30
  • Have you considered using conditional compiling? There's a good example here: http://stackoverflow.com/questions/4441397/conditional-compilation-and-objective-c-xcode – Pepe Nov 24 '13 at 08:35
  • @Pepe How is conditional compiling helping here? It certainly doesn't. OP is clearly talking about runtime. –  Nov 24 '13 at 08:47
  • @H2CO3 Ahh I missed the part where they change between runs for the same platform. I thought he meant they only changed between devices. In that case yeah it wouldn't help. Totally misread the question. – Pepe Nov 24 '13 at 08:49
  • @Pepe It wouldn't help either if it only changed between devices (that's basically the very same issue -- different devices obviously run different instances of the application.) –  Nov 24 '13 at 08:51
  • @H2CO3 Sorry if I'm not making a lot of sense, It's 3am here :) What I thought he wanted to do was for example make a label red on the iphone but green on the iPad and that those colors will never change. Again totally misread the question. – Pepe Nov 24 '13 at 08:53
  • @Pepe No problem, I answered OP's question anyway, so no harm done :) –  Nov 24 '13 at 08:54
  • possible duplicate of [Where should I store 30+ UIColors for quick reference?](http://stackoverflow.com/questions/18038953/where-should-i-store-30-uicolors-for-quick-reference) – Martin R Nov 24 '13 at 09:12
  • @MartinR I don't think that question's the same at all; I've already mentioned creating a category on `UIColor`, though the specific example is largely irrelevant to the question of declaring a function to allow for particular compiler optimisation. I actually found what I was talking about, so perhaps see my answer for more detail. – Calrion Nov 24 '13 at 09:26

4 Answers4

2

You can use a static variable. Its value will be preserved across function calls, so if you never modify it, it will store the same value during the entire lifetime of your program. Something like this:

- (UIColor *)beautifulColor
{
    static UIColor *color = nil;

    if (color == nil) {
        color = [ColorFactory randomColor];
    }

    return color;
}
2

I think you're thinking of "inlining", which is where the compiler replaces a function call with the body of the function, which avoids the minor overhead of the call.

The GCC docs say that this will happen for "simple enough" functions, presumably including a constant function like the one you're talking about.

This doesn't apply to ObjC methods, though. No method can be inlined, because of dynamic dispatch. When you write [queequeg castHarpoon];, you're just sending a message, not directly calling a method the way fabs() is a function call. queequeg might or might not actually run the method named castHarpoon. 98% of the time, that's what happens, but the object has the option, at runtime, to decide to run some other method. That means the compiler can't inline the message send with a method body.

jscs
  • 63,694
  • 13
  • 151
  • 195
0

A way to do this is to have a shared preferences object, usually a singleton, where the init functions does this lookup or calculation, and then stores it in a property.

After that point, methods needing that information would use the property. If the property is non-atomic, it should have small overhead.

If you want to avoid all overhead, declare either a static or a global variable, as in C, and set it up during startup. Not that anyone really recommends globals. Eew. :)

Hack Saw
  • 2,741
  • 1
  • 18
  • 33
0

I found it! The answer was, of course, on NSHipster and relates to the __attribute__ directive.

In my particular case, the const specifier seems to fit best:

The const attribute specifies that a function does not examine any values except their arguments, and have no effects except the return value. Note that a function that has pointer arguments and examines the data pointed to must not be declared const. Likewise, a function that calls a non-const function usually must not be const.

So I was going to declare my class method as:

+ (UIColor *)primaryTintColor __attribute__((const));

After adding the __attribute__ directive as above, the code compiled without error and behaves as expected under Xcode 5.0.2 and the iOS SDK 7.0.

But as others have pointed out in the comments below, methods resolve internally to a function that includes a pointer argument to resolve self, so __attribute__((const)) is never appropriate for methods. In this case, while it's a simple call to +[UIColor colorWithRed:green:blue:alpha:] I'll leave it as it is, but when it gets more complex—say, to slightly customise the values for different devices—I may well use a static variable to cache the value and use performance profiling to quantify any improvement.

Calrion
  • 3,202
  • 1
  • 28
  • 30
  • 2
    I'm glad you figured it out, but this doesn't affect **methods**, for the reasons given in my answer. – jscs Nov 24 '13 at 09:42
  • Thanks; I don't know much about compiler internals—is inclining the only possible optimisation here, or are there others that may apply? – Calrion Nov 24 '13 at 09:48
  • 2
    There's not much the compiler can do to optimize message sends in ObjC in the way you're thinking about, because, as I said, objects can make decisions at runtime about which method to run in response to a message. – jscs Nov 24 '13 at 09:51
  • 2
    In addition to what Josh said from the documentation you cited follows that `const` can never be applied to methods: Each method takes at least one pointer argument that has to be inspected as part of the message passing (the implicit `self` parameter). – Nikolai Ruhe Nov 24 '13 at 10:32