Static constructor equivalent in Objective-C?

24,579

Solution 1

The +initialize method is called automatically the first time a class is used, before any class methods are used or instances are created. You should never call +initialize yourself.

I also wanted to pass along a tidbit I learned that can bite you down the road: +initialize is inherited by subclasses, and is also called for each subclasses that doesn't implement an +initialize of their own. This can be especially problematic if you naively implement singleton initialization in +initialize. The solution is to check the type of the class variable like so:

+ (void) initialize {
  if (self == [MyParentClass class]) {
    // Once-only initializion
  }
  // Initialization for this class and any subclasses
}

All classes that descend from NSObject have both +class and -class methods that return the Class object. Since there is only one Class object for each class, we do want to test equality with the == operator. You can use this to filter what should happen only once ever, versus once for each distinct class in a hierarchy (which may not yet exist) below a given class.

On a tangential topic, it's worth learning about the following related methods, if you haven't already:


Edit: Check out this post by @bbum that explains more about +initialize: http://www.friday.com/bbum/2009/09/06/iniailize-can-be-executed-multiple-times-load-not-so-much/

Also, Mike Ash wrote a nice detailed Friday Q&A about the +initialize and +load methods: https://www.mikeash.com/pyblog/friday-qa-2009-05-22-objective-c-class-loading-and-initialization.html

Solution 2

There is the +initialize class method that will be called before a class is used.

Solution 3

A bit of an addendum to this topic:

There is another way to create a 'static constructor' in obj-c, using an __attribute directive:

// prototype
void myStaticInitMethod(void);

__attribute__((constructor))
void myStaticInitMethod()
{
    // code here will be called as soon as the binary is loaded into memory
    // before any other code has a chance to call +initialize.
    // useful for a situation where you have a struct that must be 
    // initialized before any calls are made to the class, 
    // as they would be used as parameters to the constructors.
    // e.g.
    myStructDef.myVariable1 = "some C string";
    myStructDef.myFlag1 = TRUE; 

    // so when the user calls the code [MyClass createClassFromStruct:myStructDef], 
    // myStructDef is not junk values.
}
Share:
24,579
Franklin Munoz
Author by

Franklin Munoz

Professional software developer in the Seattle Area, with experience on Windows & Mobile software development

Updated on January 06, 2020

Comments

  • Franklin Munoz
    Franklin Munoz over 4 years

    I'm new to Objective C and I haven't been able to find out if there is the equivalent of a static constructor in the language, that is a static method in a class that will automatically be called before the first instance of such class is instantiated. Or do I need to call the Initialization code myself?

    Thanks

  • Franklin Munoz
    Franklin Munoz about 15 years
    Thank you, that's exactly what I was looking for, but I did searches to "static init", "static initializer", etc and didn't find it.
  • Chuck
    Chuck about 15 years
    In almost every case, where in Java you'd say "static," you say "class" in Objective-C.
  • user102008
    user102008 almost 13 years
    "if ([self class] == [MyParentClass class])" [self class] is redundant here. you can just say if (self == [MyParentClass class])
  • Grady Player
    Grady Player almost 12 years
    +load will do the same thing and looks more in sync with the Objective-C paradigm
  • Richard J. Ross III
    Richard J. Ross III almost 12 years
    @Grady Nope, I specifically list a situation in the post where +load is NOT equivalent.
  • Grady Player
    Grady Player almost 12 years
    +initialize would be different, but +load should be the same shouldn't it?
  • Richard J. Ross III
    Richard J. Ross III almost 12 years
    @GradyPlayer no. Whether +initialize or +load is used, it's possible for some initial data to be corrupted. Period.
  • Grady Player
    Grady Player almost 12 years
    perhaps I don't understand the utility of createClassFromStruct: or I don't understand why you can't execute it from +load
  • Richard J. Ross III
    Richard J. Ross III almost 12 years
    Because the value of the struct is copied into the stack before the class is initialized, thus you can have invalid values.
  • Grady Player
    Grady Player almost 12 years
    what struct? myStructDef? i don't understand how that would be different than +load{myStructDef...} what error are you guarding against?
  • David Stein
    David Stein over 11 years
    Thank you! Your tidbit answered my question of why a particular static initializer was being invoked twice.
  • user102008
    user102008 about 11 years
    @RichardJ.RossIII: according to the documentation for +load, +load methods are called before __attribute__(constructor) functions
  • Richard J. Ross III
    Richard J. Ross III about 11 years
    @user102008 yes, but what you are missing is that struct values are copied to a register before the first call to +alloc.
  • Sam
    Sam about 10 years
    @RichardJ.RossIII I don't understand what you are achieving since the code in the +load method is executed before the code in a function decorated with the constructor attribute. Can you please explain? Perhaps in an edit on your answer.
  • denis631
    denis631 about 9 years
    @Sam did you understand, what is RichardJ.Rosslll talking about ? I'd like to have a real-life example...
  • Sam
    Sam about 9 years
    @denis631 no i never figured out what he's talking about.
  • denis631
    denis631 about 9 years
    @Sam I guess you would use __attribute__(constructor) in the following situation: you have 2 classes, class A and class B. You want to implement +load method for both of the classes. The problem is, class B +load method wants to call some methods from class A, but it doesn't know if class A will run +load method before B, because (in this example) it is important, that class's A +load method runs first. So the solution is to implement class A +load method, and to use __attribute__(constructor) for the class B. Now we are sure, that class A is loaded, when we want to use it in our constructor B
  • dgatwood
    dgatwood almost 8 years
    You can also use this if you're extending existing an existing class with a category in a manner that requires you to do some sort of class-level initialization up front. You can't add an initialize method in a category, because it would blow away the one in the class, and if multiple people tried to do that in multiple categories, only one of them would load, and probably nondeterministically. This, however, always works.