Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Sydde

macrumors 68030
Original poster
Aug 17, 2009
2,552
7,050
IOKWARDI
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?
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
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?

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
}
 

Sydde

macrumors 68030
Original poster
Aug 17, 2009
2,552
7,050
IOKWARDI
Don't mess around with dealloc.

You create a singleton in the +initialize method
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).
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.
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?
 

jiminaus

macrumors 65816
Dec 16, 2010
1,449
1
Sydney
Code:
static   id    singletonObject = nil;

+ (id)blankThing {
    if ( singletonObject == nil ) singletonObject =[[myClass alloc] initWithValue:@""];
    return singletonObject;
}

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.
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
That may be what you do. I find it much simpler to use the lazy method:

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.
 

Sydde

macrumors 68030
Original poster
Aug 17, 2009
2,552
7,050
IOKWARDI
And what are the consequences of creating a zombie object; particularly for future versions of the runtime.

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.
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
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.

The other option, if you are in an environment that support Grand Central Dispatch, is to use dispatch_once.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.