keeping a singleton

Discussion in 'Mac Programming' started by Sydde, May 24, 2011.

  1. macrumors 68000

    Sydde

    #1
    I have a singleton object that is approximately equivalent to something like @"" which I want to keep around. So I am looking at this, to save me having to check the object in other code:
    Code:
    - (void)dealloc {
         if ( self != theSingleltonObject ) {
              // release my ivars
              [super dealloc];
         }
    }
    I have observed that you do not seem to need -retain to prevent an object from being deallocated, just bypass the [super dealloc]. Is this behavior consistent? In my experiment, when I included -retain in the -dealloc method, it seemed to increment the retain count (the object required 2 releases to go away). Not that this would matter in this case, I was just curious if anyone knew whether I can count on not needing the -retain?
     
  2. macrumors G5

    gnasher729

    #2
    Don't mess around with dealloc.

    You create a singleton in the +initialize method (don't forget to check [self class] so you don't create another one when a subclass is initialized); that makes it threadsafe at no cost as well. Without compiling, so fix all errors first:

    Code:
    static MyClass* gMyClassSingleton;
    + (void)initialize
    {
        if ([self class] == [MyClass class]) {
            gMySingleton = [[MyClass alloc] init];
        }
    }
    
    + (MyClass*)sharedMyClass {
        return gMySingleton;
    }
    
    Then you rely on standard memory management. Anyone can call [myClass sharedMyClass], use the result, and retain and release it. If it is released too often, it goes bang! like any other object would. I don't bother doing anything special in init, but if you like you can force [[MyClass alloc] init] to return the singleton object if you do

    Code:
    - (id)init
    {
        if (gMyClassSingleton != nil && self != nil && [self class] == [MyClass class]) {
            [self release];
            return [gMyClassSingleton retain];
        }
        // The usual code goes here
    }
     
  3. macrumors 68000

    Sydde

    #3
    That may be what you do. I find it much simpler to use the lazy method:
    Code:
    static   id    singletonObject = nil;
    
    + (id)blankThing {
        if ( singletonObject == nil ) singletonObject =[[myClass alloc] initWithValue:@""];
        return singletonObject;
    }
    
    
    This way, I do not have to check whether this is the right class or not. The singleton is only visible to that one method (and other methods in that .m file).
    That is the problem. I do not want it to go "bang!". Besides conditionally bypassing [super dealloc]; is there another way to protect a singleton from going away?
     
  4. macrumors 68040

    lee1210

    #4
  5. macrumors 65816

    jiminaus

    #5
    If you do it this way, I don't see why you need to muck around with dealloc. You should always have an excess retain count because the alloc here is never matched with a dealloc. So dealloc should never be called.

    If you're coding a library that's going to be used by other unknown code, then overriding retain, release, autorelease as @lee1210 suggest is the better way. Personally, I use gnasher729's approach.

    Who knows what other housekeeping as already been cleaned-up by the runtime by the time it calls your dealloc, or after. And what are the consequences of creating a zombie object; particularly for future versions of the runtime.
     
  6. macrumors G5

    gnasher729

    #6
    Now make your code thread safe.

    +initialize is _exactly_ there for that kind of thing. +initialize is called lazily just before the first message is dispatched to your class, and in a thread-safe way. And it is a well-known (maybe not well-known enough) design pattern.
     
  7. macrumors 68000

    Sydde

    #7
    I am not sure that zombie objects exist except in a GC environment, and then only if you use -finalize improperly. I mean, an object is nothing more than a context frame. If isa is intact (the only ivar belonging to NSObject, other than perhaps retainCount), the runtime will look at that and figure out how to dispatch methods. If you bypass your regular -dealloc that releases ivars and calls [super dealloc], the context frame has not been modified or freed, so it should still be a working object. I just cannot imagine what happens between -release and -dealloc, other than the change in retain count, that would affect the validity of an object. After all, the reference is just a pointer to a frame.

    Nonetheless, I will use overrides of -release and -autorelease, just to be safe.
     
  8. Moderator

    robbieduncan

    Staff Member

    #8
    The other option, if you are in an environment that support Grand Central Dispatch, is to use dispatch_once.
     

Share This Page