73

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

Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
Franklin Munoz
  • 917
  • 1
  • 8
  • 13

3 Answers3

132

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: https://web.archive.org/web/20201108095221/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

Cœur
  • 37,241
  • 25
  • 195
  • 267
Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
  • 5
    "if ([self class] == [MyParentClass class])" `[self class]` is redundant here. you can just say `if (self == [MyParentClass class])` – user102008 Jul 22 '11 at 22:47
  • 1
    Thank you! Your tidbit answered my question of why a particular static initializer was being invoked twice. – David Stein Feb 01 '13 at 01:32
51

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

Cœur
  • 37,241
  • 25
  • 195
  • 267
Nathan Kinsinger
  • 23,641
  • 2
  • 30
  • 19
  • 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. – Franklin Munoz Jun 14 '09 at 05:26
  • 8
    In almost every case, where in Java you'd say "static," you say "class" in Objective-C. – Chuck Jun 14 '09 at 18:21
10

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.
}
Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
  • 2
    +load will do the same thing and looks more in sync with the Objective-C paradigm – Grady Player Aug 15 '12 at 17:06
  • @Grady Nope, I specifically list a situation in the post where +load is NOT equivalent. – Richard J. Ross III Aug 15 '12 at 17:18
  • +initialize would be different, but +load should be the same shouldn't it? – Grady Player Aug 15 '12 at 17:57
  • @GradyPlayer no. Whether +initialize or +load is used, it's possible for some initial data to be corrupted. Period. – Richard J. Ross III Aug 15 '12 at 18:01
  • perhaps I don't understand the utility of createClassFromStruct: or I don't understand why you can't execute it from +load – Grady Player Aug 16 '12 at 16:17
  • Because the value of the struct is copied into the stack before the class is initialized, thus you can have invalid values. – Richard J. Ross III Aug 16 '12 at 17:01
  • what struct? myStructDef? i don't understand how that would be different than +load{myStructDef...} what error are you guarding against? – Grady Player Aug 16 '12 at 18:46
  • 1
    @RichardJ.RossIII: according to the documentation for `+load`, `+load` methods are called before `__attribute__(constructor)` functions – user102008 Apr 14 '13 at 09:01
  • @user102008 yes, but what you are missing is that struct values are copied to a register *before* the first call to `+alloc`. – Richard J. Ross III Apr 14 '13 at 16:07
  • 1
    @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. – Sam Jun 23 '14 at 14:29
  • 1
    @Sam did you understand, what is RichardJ.Rosslll talking about ? I'd like to have a real-life example... – denis631 May 13 '15 at 14:16
  • @denis631 no i never figured out what he's talking about. – Sam May 14 '15 at 13:48
  • @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 – denis631 May 18 '15 at 08:12
  • 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. – dgatwood Jul 21 '16 at 23:50