Building a dynamic class factory ( +load init order)

  • Hi,

    I have some old code from the Tiger aera that fails on Leopard.
    Basically some classes call

    + (void) load
    {
    NSDictionary *aDictionary = [aDictionary dictionaryWithObjectsAndKeys:
      [self class], @"class",
      @"plugin name", @"name",
            nil]];
    [TELibraryFactory registerClass:aDictionary];
    }

    with a implementation like

    + (void) registerClass:(NSDictionary *) aClass
    {
    if( !sRegisteredClasses )
      sRegisteredClasses = [[NSMutableArray alloc] init];
    [sRegisteredClasses addObject:aClass];
    }

    Seems I relied too much that the Foundation classes are already loaded
    and initialized when  +load is called - now the dictionary creation
    already crashes.
    Is there any better way to prevent I have to add

    [[TELibraryFactory register:[TESubclass1 description]];
    [[TELibraryFactory register:[TESubclass2 description]];
    // ...
    [[TELibraryFactory register:[TESubclassN description]];

    manually in a separate file and keep that in sync each time a new
    class is added?
  • On Dec 28, 2007 7:54 PM, Thomas Engelmeier <te-work-list...> wrote:
    > NSDictionary *aDictionary = [aDictionary dictionaryWithObjectsAndKeys: ...

    Really?  That used to work?
  • Am 28.12.2007 um 22:41 schrieb Jonathan del Strother:

    > On Dec 28, 2007 7:54 PM, Thomas Engelmeier <te-work-list...>
    >> wrote:
    >> NSDictionary *aDictionary = [aDictionary
    >> dictionaryWithObjectsAndKeys: ...
    >
    > Really?  That used to work?

    Nope - similar.. Probably shouldn't write code in Mail.app with flu..

    And I´m aware the revised NSObject docs state quite clear that and why
    the implementation in +load was a pretty bad idea..

    Regards,
    Tom_E
  • Hi Thomas,

    Whatever the problem is, I don't think it's in the info you posted
    (which doesn't look like real code).

    The docs on +load are too paranoid, and are due to be revised. As of
    Leopard, you can count on all +load methods in frameworks you link to
    be called before any +load method in your code. So, what you've posted
    looks okay modulo typos.  Though, the autoreleased dictionary would
    leak and spew a log to the console due to there being no autorelease
    pool in place at this point.

    The message to TELibraryFactory is safe in that the class object will
    exist at this point, but if the class has a +load method, it may not
    have run yet.  TELibraryFactory's +load will run before that of any of
    its subclasses, though.

    Ken
    Cocoa Frameworks

    On Dec 28, 2007 2:54 PM, Thomas Engelmeier <te-work-list...> wrote:
    > Hi,
    >
    > I have some old code from the Tiger aera that fails on Leopard.
    > Basically some classes call
    >
    > + (void) load
    > {
    > NSDictionary *aDictionary = [aDictionary dictionaryWithObjectsAndKeys:
    > [self class], @"class",
    > @"plugin name", @"name",
    > nil]];
    > [TELibraryFactory registerClass:aDictionary];
    > }
    >
    > with a implementation like
    >
    > + (void) registerClass:(NSDictionary *) aClass
    > {
    > if( !sRegisteredClasses )
    > sRegisteredClasses = [[NSMutableArray alloc] init];
    > [sRegisteredClasses addObject:aClass];
    > }
    >
    > Seems I relied too much that the Foundation classes are already loaded
    > and initialized when  +load is called - now the dictionary creation
    > already crashes.
    > Is there any better way to prevent I have to add
    >
    >
    > [[TELibraryFactory register:[TESubclass1 description]];
    > [[TELibraryFactory register:[TESubclass2 description]];
    > // ...
    > [[TELibraryFactory register:[TESubclassN description]];
    >
    > manually in a separate file and keep that in sync each time a new
    > class is added?
    >
  • On 29.12.2007, at 00:27, Ken Ferry wrote:

    Hi Ken,

    > Whatever the problem is, I don't think it's in the info you posted
    > (which doesn't look like real code).

    For debugging purposes the real code was a comment-out mess.
    *sigh* I pinned it down to an typo in the real code, actually an "C-
    string" literal instead of an @"NSString".  I really shouldn't code
    influenced by some influenca...

    Debugging was partially tricky, Xcode / gdb most of the time failed
    with a sigsegv, alternating with
    "Xcode: Introspection dylib not loaded because thread 1 has function:
    __dyld__ZN4dyld12notifySingleE17dyld_image_statesPK11mach_headerPKcl
    on stack", i.e. dyld::notifySingle(dyld_image_states, mach_header
    const*, char const*, long).

    > The docs on +load are too paranoid, and are due to be revised. As of
    > Leopard, you can count on all +load methods in frameworks you link to
    > be called before any +load method in your code.

    OK, great for the clarification. Otherwise I had rewritten the code
    anyway.

    > Though, the autoreleased dictionary would
    > leak and spew a log to the console due to there being no autorelease
    > pool in place at this point.

    Thanks for that hint.

    > The message to TELibraryFactory is safe in that the class object will
    > exist at this point, but if the class has a +load method, it may not
    > have run yet.  TELibraryFactory's +load will run before that of any of
    > its subclasses, though.

    My first variant used a C function to prevent any race conditions. So
    the Leopard +load order is also baseclass to subclasses, like
    +initialize?

    Thanks,
    Tom_E
previous month december 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Go to today