4
votes

I have a managed core data object with a +initialize method. (If it matters, I am looking to use that method to initialize a static variable that is expensive to to set up.) While testing that initialization code I was surprised to discover that the +initialize method is getting called twice.

The first time initialize is being called self is defined as (Class) MyClass, as I would expect.

The second time initialize is being called self is defined as (Class) MyClass_MyClass_, which leads me to suspect some sort of unusual initialization for Core Data managed objects.

While this doesn't pose a problem for me (I can just test to see if the static variable has already been initialized, which I would do anyway, to handle ubclassing), it makes me suspect that Core Data is doing something in the object or class lifecycle that I don't understand. Can someone explain to me what is going on in this MyClass_MyClass_ +initialize method invocation?

2
To clarify, I understand +initialize, it just seems that the implementation of Core Data is creating a subclass of the object behind the scenes. I wondered what that subclass is doing.David Ogren

2 Answers

5
votes

The accessor methods for Core Data properties are dynamically created at runtime. This works by creating a subclass MyClass_MyClass_ (of MyClass) and adding the necessary methods to the subclass.

Core Data also does some tricks to hide the fact that that the objects of your entity are actually instances of the subclass:

e = [NSEntityDescription insertNewObjectForEntityForName:@"MyClass" inManagedObjectContext:context];
NSLog(@"%@", [e class]);               // --> MyClass
NSLog(@"%s", object_getClassName(e));  // --> MyClass_MyClass_

Perhaps it becomes even more obvious if you don't set a custom class for your entity. In that case the output is

NSLog(@"%@", [e class]);               // --> NSManagedObject
NSLog(@"%s", object_getClassName(e));  // --> NSManagedObject_MyClass_

So e "looks like" an instance of NSManagedObject, but is indeed an instance of a dynamically created subclass NSManagedObject_<EntityName>_. This subclass implements all the accessor methods (which are unique to this entity).

0
votes

From Apples documentation on NSObject I gather it is normal behaviour: The runtime sends initialize to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program. The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses. The superclass implementation may be called multiple times if subclasses do not implement initialize—the runtime will call the inherited implementation—or if subclasses explicitly call [super initialize]. If you want to protect yourself from being run multiple times, you can structure your implementation along these lines...

+ (void)initialize {
    if (self == [ClassName class]) {
    // ... do the initialization ...
   }
}

Why you don't use the awakeFrom... methods NSManagedObject offers?